CodeForces 254 E Dormitory

39 篇文章 0 订阅

题目

题意:

一个人,每天有食物供应,除了自己吃之外还可以给同学吃,或者将今天的食物留到明天,但不能留到后天。每天每个朋友只能喂一次,每喂一次加1点受欢迎度。求n天后的最大受欢迎度。

题解:

DP,记录昨天剩下多少食物,并且每天计算喂i个朋友的最小花费。注意食物不能留到第三天。

本来以为400^3要很久呢,没想到CF升级后这么快了。

//Time:62ms
//Memroy:3600KB
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#include <map>
#include <queue>
#include <set>
#define MAXN 410
#define INF 1000000007
#define MP(x,y) make_pair(x,y)
#define FI first
#define SE second
#define EPS 1e-8
using namespace std;
int dp[MAXN][MAXN];
int a[MAXN],f[MAXN],top,who[MAXN];
int efa[MAXN][MAXN],eat[MAXN][MAXN];
pair<int,int> pa[MAXN*2],fa[MAXN][MAXN];
set<pair<int,int> >se;
int main()
{
    //freopen("/home/moor/Code/input","r",stdin);
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int n,v,m,ans,pos;
    while(scanf("%d%d",&n,&v)==2)
    {
        for(int i=0;i<n;++i)    scanf("%d",&a[i]);
        scanf("%d",&m);
        top=0;
        for(int i=1;i<=m;++i)
        {
            int l,r;
            scanf("%d%d%d",&l,&r,&f[i]);
            pa[top++]=MP(r+1,-i);
            pa[top++]=MP(l,i);
        }
        sort(pa,pa+top);
        memset(dp,-0x3f,sizeof(dp));
        dp[0][0]=0;
        se.clear();
        set<pair<int,int> >::iterator ite;
        for(int i=0,j=0;i<n;++i)
        {
            while(j<top&&pa[j].FI==i+1)
            {
                int tmp=f[abs(pa[j].SE)];
                if(pa[j].SE>0)
                    se.insert(MP(tmp,pa[j].SE));
                else
                    se.erase(MP(tmp,-pa[j].SE));
                ++j;
            }
            ite=se.begin();
            eat[i][0]=0;
            for(int k=1;ite!=se.end();++k,++ite)
                eat[i][k]=eat[i][k-1]+ite->FI,efa[i][k]=ite->SE;
            for(int k=0,l=0;k<=(i>0?a[i-1]:0);++k)
                if(dp[i][k]>=0&&k+a[i]>=v)
                {
                    int tmp=k-v;
                    while((unsigned)l+1<=se.size()&&tmp-eat[i][l+1]>0)   ++l;
                    tmp+=a[i];
                    for(int p=l;tmp-eat[i][p]>=0&&(unsigned )p<=se.size();++p)
                        if(dp[i+1][min(tmp-eat[i][p],a[i])]<dp[i][k]+p)
                        {
                            dp[i+1][min(tmp-eat[i][p],a[i])]=dp[i][k]+p;
                            fa[i+1][min(tmp-eat[i][p],a[i])]=MP(p,k);
                        }
                }
        }
        ans=0,pos=0;
        for(int i=0;i<MAXN;++i)
            if(ans<=dp[n][i])
                ans=dp[n][i],pos=i;
        for(int i=n;i>0;--i)
        {
            pos=min(pos,a[i-1]);
            who[i-1]=fa[i][pos].FI,pos=fa[i][pos].SE;
        }
        printf("%d\n",ans);
        for(int i=0;i<n;++i)
        {
            printf("%d",who[i]);
            for(int j=1;j<=who[i];++j)
                printf(" %d",efa[i][j]);
            printf("\n");
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值