2017/9/26Codeforces E题
我终于打了一场cf了,可惜我太蒟蒻,6题才出了4题,反思一下,订正一下吧
E题面:http://codeforces.com/contest/864/problem/E
E题大意:
Polycarp家着火了,现在Polycarp要把一些东西救出来,每样东西都有三个值ti(救出来所花的时间),di(物品被烧毁的时间,只有物品在被烧毁前救出来才有价值),pi(物品价值)
输入:一个N(1≤N≤100),之后N行每行三个数ti(1≤ti≤20),di(1≤di≤2000),pi(1≤pi≤20)
输出:第一行是最大救出的价值,第二行输出被救出的物品数量,第三行按被救顺序输出每个物品的编号(编号为物品输入顺序),若有多种方案则输出一种
样例输入1
3
3 7 4
2 6 5
3 7 6
样例输出1
11
2
2 3
样例输入2
2
5 6 1
3 3 5
样例输出2
1
1
1
题目不难,想一想O(n^2)能过,刚开始看想个背包,然后呢发现,好像就是啊,只是物品会被烧毁,那么就大力DP一发吧
既然是想O(n^2)的转移,那么一维转移物品一维用作时间
f[i]表示到第i的时间所获取的价值最大值
状态转移
f[i]=max(f[i−t[a]]+p[a])(1≤a≤N且d[a]>f[i])
是不是感觉很easy?
然而,要怎么样放才能保证转移不因为被烧毁时间而挂掉呢
由于我偷懒,所以在考场上我按di-ti排序,然后成功WA
为什么呢?因为有这样的情况:
p1=8 , d1=10,p1=10
p2=1 , d2=4 , p2=10
答案是20我的程序输出10
那怎么办呢?
直接按di排序就好啦
为什么呢?
假设两个物品a,b能同时救出,那么一定满足这个情况
若a被摧毁时间比b早
若a被摧毁时间比b晚
(因为保证能同时存在所以b被摧毁的时间一定在a、b被救出来之后)
然后就好啦
放一下代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline void read(int&x)
{
char cu=getchar();x=0;bool fla=0;
while(cu<'0'||cu>'9'){if(cu=='-')fla=1;cu=getchar();}
while('0'<=cu&&cu<='9')x=x*10+cu-'0',cu=getchar();
if(fla)x=-x;
}
void printe(const int x)
{
if(x>=10)printe(x/10);
putchar(x%10+'0');
}
inline void print(const int x)
{
if(x<0)putchar('-'),printe(-x);
else printe(x);
}
int N;
struct things
{
int t,d,p,ended,id;//在ended时刻之前救该物品才有效,id即编号
}t[101];
int cmp(things x,things y)
{
return x.d<y.d;
}
int dp[2001],from[2001][2001],ans=-1,wz;
int main()
{
memset(dp,-1,sizeof(dp));
read(N);
for(int i=1;i<=N;i++)
read(t[i].t),read(t[i].d),read(t[i].p),t[i].id=i;
sort(t+1,t+N+1,cmp);//排序,尤其注意
for(int i=1;i<=N;i++)t[i].ended=t[i].d-t[i].t;//算出ended
dp[0]=0;
for(int i=1;i<=N;i++)
{
if(t[i].ended<=0)continue;//特判
for(int j=t[i].ended-1;j>=0;j--)
{
if(dp[j]==-1)continue;//特判
if(dp[j]+t[i].p>dp[j+t[i].t])
{
dp[j+t[i].t]=dp[j]+t[i].p;//转移
memcpy(from[j+t[i].t],from[j],sizeof(from[j+t[i].t]));
from[j+t[i].t][++from[j+t[i].t][0]]=t[i].id;//更新
}
}
}
for(int i=0;i<=2000;i++)//找出答案
if(dp[i]>ans)
{
ans=dp[i];
wz=i;
}
print(ans);
putchar('\n');
print(from[wz][0]);
putchar('\n');
if(from[wz][0]!=0)
{
print(from[wz][1]);
for(int i=2;i<=from[wz][0];i++)putchar(' '),print(from[wz][i]);
}
return 0;
}