2019.11.30 垃圾陷阱
题目描述
卡门――农夫约翰极其珍视的一条Holsteins
奶牛――已经落了到“垃圾井”中。“垃圾井”是农夫们扔垃圾的地方,它的深度为\(D(2 \le D \le 100)\)英尺。
卡门想把垃圾堆起来,等到堆得与井同样高时,她就能逃出井外了。另外,卡门可以通过吃一些垃圾来维持自己的生命。
每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间。
假设卡门预先知道了每个垃圾扔下的时间\(t(0< t \le 1000)\),以及每个垃圾堆放的高度\(h(1 \le h \le 25)\)和吃进该垃圾能维持生命的时间\(f(1 \le f \le 30)\),要求出卡门最早能逃出井外的时间,假设卡门当前体内有足够持续\(10\)小时的能量,如果卡门\(10\)时内没有进食,卡门就将饿死。
输入格式
第一行为\(2\)个整数,\(D\)和 \(G (1 \le G \le 100)\),\(G\)为被投入井的垃圾的数量。
第二到第\(G+1\)行每行包括\(3\)个整数:\(T (0 < T <= 1000)\),表示垃圾被投进井中的时间;\(F (1 \le F \le 30)\),表示该垃圾能维持卡门生命的时间;和 \(H (1 \le H \le 25)\),该垃圾能垫高的高度。
输出格式
如果卡门可以爬出陷阱,输出一个整数表示最早什么时候可以爬出;否则输出卡门最长可以存活多长时间。
输入输出样例
输入 #1
20 4
5 4 9
9 3 2
12 6 10
13 1 1
输出 #1
13
说明/提示
[样例说明]
卡门堆放她收到的第一个垃圾:\(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
*/