题目有难度,第一题为dp,第二题要用平衡树,第三题最短路+判负环+二分
小奇挖矿
题目描述
【题目背景】
小奇要开采一些矿物,它驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞过喵星系的n个星球。
【问题描述】
星球分为2类:资源型和维修型。
1.资源型:含矿物质量a[i],若选择开采,则得到a[i]*p的金钱,之后钻头损耗k%,即p=p*(1-0.01k)
2.维修型:维护费用b[i],若选择维修,则支付b[i]*p的金钱,之后钻头修复c%,即p=p*(1+0.01c)
(p为钻头当前能力值)
注:维修后钻头的能力值可以超过初始值
请你帮它决策最大化这个收入
【输入格式】
第一行4个整数n,k,c,w。
以下n行,每行2个整数type,x。
type为1则代表其为资源型星球,x为其矿物质含量a[i];
type为2则代表其为维修型星球,x为其维护费用b[i];
【输出格式】
输出一行一个实数(保留两位小数),表示要求的结果。
【样例输入】
5 50 50 10
1 10
1 20
2 10
2 20
1 30
【样例输出】
375.00
【数据范围】
对于30%的数据 n<=100
对于50%的数据 n<=1000,k=100
对于100%的数据 n<=100000,0<=k,c,w,a[i],b[i]<=100
保证答案不超过10^9
首先要进行转换,要明白能力值可以分成若干个单位长度进行挖矿或修复操作,即我们只需算出一个单位长度的最大解,再乘以初始能力值就是最终答案
所以开一个一维数组,在考虑递推顺序,因为i号的决策只对后面的产生影响,所以选择从后往前推,注意,dp【i】指从i到n的最优解
所以得出转移方程dp[i]=max(dp[i+1],dp[i+1]*(1-0.01*k)+x[i]) 这是type为一的情况,dp[i+1]*(1-0.01*k)是因为如果要挖当前的矿,后面的就会被损耗
同理可得type为二的转移(见代码
当然可以直接滚动,不用开数组(太懒难得写
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e5+10; 4 inline int read(){ 5 int x=0,f=1;char ch=getchar(); 6 while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} 7 while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} 8 return x*f; 9 } 10 11 double dp[maxn]; 12 13 int type[maxn],x[maxn],n,k,c,w; 14 15 int main(){ 16 n=read(),k=read(),c=read(),w=read(); 17 for(int i=1;i<=n;i++) type[i]=read(),x[i]=read(); 18 for(int i=n;i>0;i--){ 19 if(type[i]==1) dp[i]=max(dp[i+1],dp[i+1]*(1-0.01*k)+x[i]); 20 else dp[i]=max(dp[i+1],dp[i+1]*(1+0.01*c)-x[i]); 21 } 22 printf("%.2f",dp[1]*w); 23 return 0; 24 }
小奇的数列
题目描述
【题目背景】
小奇总是在数学课上思考奇怪的问题。
【问题描述】
给定一个长度为n的数列,以及m次询问,每次给出三个数l,r和P,询问 (a[l'] + a[l'+1] + ... + a[r']) mod P的最小值。
其中l <= l' <= r' <= r。
即模意义下的区间子串和最小值。
【输入格式】
第一行包含两个正整数n和m,表示数列的长度和询问的个数。
第二行为n个整数,为a[1]..a[n]。
接下来m行,每行三个数l,r和P,代表一次询问。
【输出格式】
对于每次询问,输出一行一个整数表示要求的结果
【样例输入】
4 2
8 15 9 9
1 3 10
1 4 17
【样例输出】
2
1
【数据范围】
对于20%的数据 n<=100,m<=100,p<=200
对于40%的数据 n<=200,m<=1000,p<=500
对于70%的数据 n<=100000,m<=10000,p<=200
对于100%的数据 n<=500000,m<=10000,p<=500,1<=a[i]<=10^9
小奇回地球
题目描述
【题目背景】
开学了,小奇在回地球的路上,遇到了一个棘手的问题。
【问题描述】
简单来说,它要从标号为1的星球到标号为n的星球,某一些星球之间有航线。由于超时空隧道的存在,从一个星球到另一个星球时间可能会倒流,而且,从星球a到b耗费的时间和星球b到a耗费的时间不一定相同。
宇宙法规定:“禁止在出发时间前到达目的地。”
每艘飞船上都有速度调节装置,可以调节飞行的时间。其功能可以使得整次航程中所有两星球间的飞行时间增加或减少相同的整数值。你的任务是帮助它调整速度调节器,找出一条最短时间到达目的地的路径。
【输入格式】
输入文件包含多组数据,第1个数为T,表示数据组数。
对于每组数据,输入第1行为两个正整数n,m,为星球的个数和星球间的路线数。接下来m行,每行三个整数i,j和t,表示由星球i到星球j飞行的时间为t。由i到j最多只会有一条飞行线路。
【输出格式】
输出文件共T行,每组数据输出一行。
如果可以通过调节速度调节器完成任务,则输出一个非负整数,表示由星球1到星球n的最短时间。(注意最短时间要大于或者等于0)。
如果不能由星球1到达星球n,则输出-1。
【样例输入】
1
4 5
1 2 1
1 3 1
2 3 -3
3 1 1
3 4 1
【样例输出】
2
【样例解释】
把速度控制器的值设为1,相当于每个时间值加1,得到的最短路径为1→2→3→4,所需时间为2+(-2)+2=2。
【数据范围】
1,2号测试点,保证所有星球出度不超过1
3,4号测试点,n<=10
5,6号测试点,-100<=t<=100
对于100%的数据T<=10,n<=100,m<=n*(n-1),-100000<=t<=100000
数据随机和构造结合生成
一道很好的题目,坑点很多
首先说基本思路
1.先dfs找与1到n的路径无关的点删除,具体实现看代码
2.二分改变路径长度的指,我是减去当前值,也可以加,位置换下就行
3.判负环,这里用的是dfs版的spfa,会快一点
4.spfa跑最短路,如果dis[n]>=0 ans更新,再向右推
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxm = 10000+10; 4 const int maxn = 110; 5 const int inf = 0x3f3f3f3f; 6 inline int read(){ 7 int x=0,f=1;char ch=getchar(); 8 while(ch>'9'||ch<'0') {if(ch=='-') f=-1;ch=getchar();} 9 while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} 10 return f*x; 11 } 12 int n,m,dis[maxn],head[maxn],ans,size,q[105],mid; 13 bool con[maxn],bj[maxn],vis[maxn]; 14 struct edge{ 15 int v,nex,w; 16 }e[maxm]; 17 18 void adde(int u,int v,int w){ 19 e[size].v=v; 20 e[size].w=w; 21 e[size].nex=head[u]; 22 head[u]=size++; 23 } 24 25 void dfscon(int x){//找无关点 26 bj[x]=1; 27 for(int i=head[x];~i;i=e[i].nex){ 28 int v=e[i].v; 29 if(!bj[v]) 30 dfscon(v); 31 } 32 } 33 34 bool dfs(int u){//判负环 35 vis[u]=1; 36 for(int i=head[u];~i;i=e[i].nex){ 37 int v=e[i].v,w=e[i].w-mid; 38 if(dis[v]>dis[u]+w&&con[v]){ 39 if(vis[v]) return false; 40 dis[v]=dis[u]+w; 41 if(!dfs(v)) return false; 42 } 43 } 44 vis[u]=0; 45 return true; 46 } 47 48 void spfa(){//标准spfa 49 for(int i=1;i<=n;i++) dis[i]=inf,vis[i]=0; 50 int h=0,t=1; 51 q[0]=1;vis[1]=1;dis[1]=0; 52 while(h!=t){//用的手工队列 53 int u=q[h];h++;if(h==100) h=0; 54 for(int i=head[u];~i;i=e[i].nex){ 55 if(dis[e[i].v]>dis[u]+e[i].w-mid&&con[e[i].v]) 56 { 57 dis[e[i].v]=dis[u]+e[i].w-mid; 58 if(!vis[e[i].v]){ 59 vis[e[i].v]=1; 60 q[t++]=e[i].v;if(t==100) t=0; 61 } 62 } 63 } 64 vis[u]=0; 65 } 66 } 67 68 bool jud() 69 { 70 for(int i=1;i<=n;i++) 71 if(con[i]) 72 { 73 for(int j=1;j<=n;j++) dis[j]=inf; 74 memset(vis,0,sizeof(vis)); 75 if(!dfs(i)) return false; 76 } 77 spfa(); 78 if(dis[n]>=0&&dis[n]!=inf) return 1; 79 return 0; 80 81 } 82 83 int main(){ 84 //freopen("in.txt","r",stdin); 85 int t=read(); 86 while(t--){ 87 memset(head,-1,sizeof(head)); 88 memset(bj,0,sizeof(bj)); 89 memset(con,1,sizeof(con)); 90 size=0; 91 ans=-1; 92 n=read(),m=read(); 93 for(int i=1;i<=m;i++) { 94 int u=read(),v=read(),w=read(); 95 adde(u,v,w); 96 } 97 dfscon(1); 98 for(int i=1;i<=n;i++) if(!bj[i]) con[i]=0; 99 for(int i=1;i<=n;i++) 100 if(con[i]){ 101 memset(bj,0,sizeof(bj)); 102 dfscon(i); 103 if(!bj[n]) con[i]=0; 104 } 105 int r=100000,l=-100000; 106 while(l<=r){ 107 mid=(l+r)>>1; 108 if(jud()) { 109 ans=dis[n];l=mid+1; 110 } 111 else r=mid-1; 112 } 113 printf("%d ",ans); 114 } 115 return 0; 116 }