2017/9/26Codeforces E题

11 篇文章 0 订阅
4 篇文章 0 订阅

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[it[a]]+p[a])(1aNd[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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值