2017.10.26 星际贸易 思考记录

这个题非常繁琐,而且网上的题解非常不详细。。

首先第一问

由于所有的点都要走到,所以就是01背包

需要可持久化背包来输出方案。。类似floyd的判断方式

然后这些选定的点都一定是要维护的,

第二问就是枚举每个点+每个点的加速器数量 来 dp

然后n^4的dp就是从1到n枚举i,从1到i枚举j,从0到r枚举j的加速器个数k   ,从0到r枚举i的加速器个数l,然后转移


然后可以优化 ,由于对于   枚举的每一个j   当k相同的时候只从j中选最优的更新 ,只要 求i对于每个k的前面的最优值即可,可以证明这是贪心取,(只要合法,就去花费最小的)

然后就顺带出一个类似飞扬的小鸟的更新方法,同级更新,一直选择最优的往上买,,

对于买加速器的情况就变成O(1)的顺带转移了



码:

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,r,l0,k,v[4002],ans1,ans2=1000000009,c[4002],l[4002],p[4002],wh[4002],i,j,f[4003][4003],q[5003][5003],z1[5003],z2[5003];
bool bj[4002];
int main()
{
    scanf("%d%d%d%d",&n,&m,&r,&l0);
    r=min(r,n*2);
    for(i=1;i<=n;i++)
   {
    scanf("%d%d%d%d%d",&c[i],&v[i],&l[i],&p[i],&wh[i]);     
   }
    for(i=1;i<=m;i++)
    for(j=1;j<=n;j++)
    f[j][i]=-1000000009;
    f[0][0]=0;
        for(j=1;j<=n;j++)
        {
        for(i=m;i>=0;i--)
    {
        f[j][i]=f[j-1][i];
        if(i>m-c[j])continue;
        if(f[j][i+c[j]]<f[j-1][i]+v[j])
        {
        f[j][i+c[j]]=f[j-1][i]+v[j];            
        if(f[j][i+c[j]]>ans1)
        {
            ans1=f[j][i+c[j]];
            ans2=i+c[j];
        }
        }   
    }       
        }
        int lin=ans1,lin2=ans2;
if(lin2<1000000009)  for(i=n;i>=1;i--)
    {
        if(lin2-c[i]>=0&&f[i-1][lin2-c[i]]+v[i]==lin)
        {
            bj[i]=1;    
            lin=f[i-1][lin2-c[i]];
            lin2=lin2-c[i];
        }           
    }
    //ans1=f[ans1][0];
    for(i=0;i<=n;i++)
    for(j=0;j<=r+2;j++)
    f[i][j]=1000000009,z2[j]=-1;
    ans2=1000000009;
    f[0][r]=0;
    q[r][++z2[r]]=0;
    for(i=1;i<=n;i++)
    {
        for(j=2;j<=r+2;j++)//枚举上一个更新这一个 
        {
        if(j!=2&&p[i]>0)f[i][j-2]=f[i][j-3]+p[i];
        while(z1[j]<=z2[j]&&(l[i]-l[q[j][z1[j]]]>l0))z1[j]++;
            if(j<=r)
            {
         int l1=l[i]-l[q[j][z1[j]]];
			if(l0>=l1)
			if(f[i][j-2]>f[q[j][z1[j]]][j]) 
			     f[i][j-2]=f[q[j][z1[j]]][j];   
            }
            while(z1[j-2]<=z2[j-2]&&l[i]-l[q[j-2][z1[j-2]]]>l0)
			z1[j-2]++;
            if(bj[i])while(z2[j-2]>=z1[j-2])z1[j-2]++;
        while(z1[j-2]<=z2[j-2]&&f[i][j-2]+wh[i]<f[q[j-2][z2[j-2]]][j-2])z2[j-2]--;
        q[j-2][++z2[j-2]]=i;
        }
        for(j=0;j<=r;j++)
        f[i][j]+=wh[i]; 
    }
    for(i=0;i<=r;i++)
    if(f[n][i]<ans2)ans2=f[n][i];
    if(ans2<1000000009)printf("%d %d",ans1,ans1-ans2);   
    else printf("Poor Coke!");
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值