卡门――农夫约翰极其珍视的一条Holsteins
奶牛――已经落了到“垃圾井”中。“垃圾井”是农夫们扔垃圾的地方,它的深度为\(D(2 \le D \le 100)\)英尺。ios
卡门想把垃圾堆起来,等到堆得与井一样高时,她就能逃出井外了。另外,卡门能够经过吃一些垃圾来维持本身的生命。git
每一个垃圾均可以用来吃或堆放,而且堆放垃圾不用花费卡门的时间。数组
假设卡门预先知道了每一个垃圾扔下的时间\(t(0< t \le 1000)\),以及每一个垃圾堆放的高度\(h(1 \le h \le 25)\)和吃进该垃圾能维持生命的时间\(f(1 \le f \le 30)\),要求出卡门最先能逃出井外的时间,假设卡门当前体内有足够持续\(10\)小时的能量,若是卡门\(10\)时内没有进食,卡门就将饿死。spa
第一行为\(2\)个整数,\(D\)和 \(G (1 \le G \le 100)\),\(G\)为被投入井的垃圾的数量。code
第二到第\(G+1\)行每行包括\(3\)个整数:\(T (0 < T <= 1000)\),表示垃圾被投进井中的时间;\(F (1 \le F \le 30)\),表示该垃圾能维持卡门生命的时间;和 \(H (1 \le H \le 25)\),该垃圾能垫高的高度。排序
若是卡门能够爬出陷阱,输出一个整数表示最先何时能够爬出;不然输出卡门最长能够存活多长时间。get
输入 #1string
20 4 5 4 9 9 3 2 12 6 10 13 1 1
输出 #1it
13
[样例说明]io
卡门堆放她收到的第一个垃圾:\(height=9\);
卡门吃掉她收到的第\(2\)个垃圾,使她的生命从\(10\)时延伸到\(13\)时;
卡门堆放第\(3\)个垃圾,\(height=19\);
卡门堆放第\(4\)个垃圾,\(height=20\)。
对于每一个垃圾,咱们有两种处理方法:吃掉或者垫起来。
这透露出浓浓的背包气息。考虑\(dp\)。
对于整个题来说,咱们有\(4\)个变量:当前时间/垃圾的编号/当前高度/当前生命。
这样空间开不下,可是咱们容易观察到对于每一个垃圾,没有必要留着而应该直接使用,因此当前时间能够和垃圾的编号合并。
这样只有了\(3\)个变量。题目里面要求求出达到高度\(d\)的最短期,因此咱们用\(dp[i][j]\)表示当降下第\(i\)道垃圾且处理完这个垃圾以后的生命为\(j\)时,最大能够到达的高度。原题里面不少题解都是用\(dp[i][j]\)表示最大生命,不知道为何。
请注意这里的生命是从\(0\)时刻开始可以存活的总生命值。也就是说这个生命不会递减只会增长,判断死亡的标准是当前的生命值小于当前时间点。
对于每一个垃圾,咱们有两种选择:
第一,利用它提高高度。那么\(dp[i][j]=dp[i-1][j]+h[i]\),表示第\(i\)个垃圾被用来提高了\(h[i]\)的高度。
第二,利用它回复生命。那么\(dp[i][j]=dp[i-1][j-f[i]]\),表示第\(i\)个垃圾被用来回复了\(f[i]\)的生命。
当咱们第一次找到了\(dp[i][j]\geq d\),则输出\(t[i]\)以后\(return 0\),由于垃圾是按照时间顺序枚举的。
若是找不到知足要求的答案,说明没法跳出。这时咱们的判断策略有变化,由于要尽量活下去,也就是说应该用全部的垃圾回复生命。因此对于每个垃圾落下的时间,咱们发现它大于当前的生命值则输出当前生命值并结束;不然生命值加上这个垃圾的回复量。
注意事项有三点:
第一,若是利用垃圾回复生命,必须判断\(j-f[i]\geq t[i]\),由于\(dp[i][j]\)的第二维表示的是处理完这个垃圾以后的生命,咱们必须判断原来的生命能不能坚持到这个时间点。判断的方法如上,由于生命值的定义是从\(0\)开始能坚持多长时间,与时间的增加等速同向。忘记这个点会丢失\(10-30pts\)。
第二,请记得给输入按时间排序。题目中没有表示全部圣诫之光按照时间给出,忘记这个点会丢失\(20pts\)。
第三,请记得初始化\(dp\)数组为\(-inf\)。由于如\(dp[0][9]\)之类的状态走不到。
上代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cctype> #include<cmath> #define int long long #define rep(i,a,n) for(register int i=a;i<=n;++i) #define dwn(i,n,a) for(register int i=n;i>=a;--i) using namespace std; int d,g,t[100050],f[100050],h[100050],dp[105][3050]; struct rub { int t,f,h; }a[100050]; inline int read() { int x=0,f=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } void write(int x) { if(x<0)putchar('-'),x=-x; if(x==0)return; write(x/10); putchar(x%10+'0'); } bool cmp(rub a,rub b) { if(a.t==b.t) { if(a.f==b.f)return a.h<b.h; else return a.f<b.f; } return a.t<b.t; } signed main() { d=read(),g=read(); rep(i,1,g)a[i].t=read(),a[i].f=read(),a[i].h=read(); sort(a+1,a+g+1,cmp); memset(dp,128,sizeof dp); dp[0][10]=0; rep(i,1,g) { rep(j,max(a[i].t,a[i].f),a[g].t+1) { dp[i][j]=dp[i-1][j]+a[i].h; if(j-a[i].f>=a[i].t)dp[i][j]=max(dp[i][j],dp[i-1][j-a[i].f]); // printf("%lld %lld %lld\n",i,j,dp[i][j]); if(dp[i][j]>=d) { write(a[i].t); return 0; } } } int last=10; a[g+1].t=0x3f3f3f3f; rep(i,1,g+1) { if(last<a[i].t) { write(last); return 0; } last+=a[i].f; } return 0; } /* 6 5 10 30 5 40 30 5 70 30 5 100 30 5 130 2 5 */