CF922E Birds 题解

题目传送门

前置知识

背包 DP

解法

观察到 \(w\) 极大,若使用正常的背包空间会爆炸。

依据 AT_dp_e Knapsack 2 的经验,考虑将背包“反”着用。设 \(f_{i,j}\) 表示到第 \(i\) 棵树时一共召唤了 \(j\) 只小鸟时剩余的最大魔力值,状态转移方程为 \(f_{i,j}=\min(\max\limits_{k=0}^{\min(j,c_{i})} \{ f_{i-1,j-k}-cost_{i} \times k+x \},w+b \times j)\),边界为 \(f_{0,0}=w\)

最终,有 \(\max\limits_{i=0}^{\sum_{j=1}^{n}c_{j}} \{ [f_{n,i} \ge 0] \times i \}\) 即为所求。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define ull unsigned long long
#define sort stable_sort 
#define endl '\n'
ll c[10010],sum[10010],cost[10010],f[1010][10010];
int main()
{
    ll n,w,b,x,ans=0,i,j,k;
    cin>>n>>w>>b>>x;
    for(i=1;i<=n;i++)
    {
        cin>>c[i];
        sum[i]=sum[i-1]+c[i];
    }
    for(i=1;i<=n;i++)
    {
        cin>>cost[i];
    }
    memset(f,-0x3f,sizeof(f));
    f[0][0]=w;
    for(i=1;i<=n;i++)
    {
        for(j=0;j<=sum[i];j++)
        {
            for(k=0;k<=min(j,c[i]);k++)
            {
                if(f[i-1][j-k]-cost[i]*k>=0)
                {
                    f[i][j]=max(f[i][j],f[i-1][j-k]-cost[i]*k+x);
                }
            }
            f[i][j]=min(f[i][j],w+b*j);
        }
    }
    for(i=sum[n];i>=0;i--)
    {
        if(f[n][i]>=0)
        {
            ans=i;
            break;
        }
    }
    cout<<ans<<endl;
    return 0;
} 		   		     	
posted @ 2024-03-23 22:29  hzoi_Shadow  阅读(2)  评论(0编辑  收藏  举报
扩大
缩小