有n棵树,每棵树Ci个鸟,买一个花费Costi元。最开始钱包容量和钱数都是w元,且买一个鸟钱包容量增加一个定值。现在按顺序从1号树走到n号树,每换一棵树多出来x元,最多买多少鸟?
明显的一个DP,容易看出现在走到第i棵树可以作为DP的一维。
看题之后发现,费用数量很大,可能有1e9,显然费用不能作为DP的一维。而影响买鸟数量的因素,除了费用就是钱包容量了。而且,当鸟的数量一定时,钱包容量是相等的!
由此,我们可以把鸟的数量当做DP的另一维,去找每个对应的DP状态的剩下的钱最多是多少。
dp[i][j]表示走到第i棵树下,买了j个鸟剩下的钱数最多是多少,最后只要找dp[n][j]>=0的最大的j,就是答案。
转移方程:dp[i][j]=max(dp[i-1][j-k]-k*cost[i]),k表示在当前这棵树上买的鸟数,0<=k<=Ci.
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int maxn=1005,maxk=10005,inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
ll a[maxn],c[maxn];
ll dp[maxn][maxk];
int main() {
ll n,w,b,x,i,j,k;
scanf("%I64d%I64d%I64d%I64d",&n,&w,&b,&x);
for (i=1;i<=n;i++)
scanf("%I64d",&a[i]);
for (i=1;i<=n;i++)
scanf("%I64d",&c[i]);
memset(dp,-1,sizeof(dp));
dp[0][0]=w;
ll sum=0;
for (i=1;i<=n;i++) {
sum+=a[i];
ll cap=w;
for (j=0;j<=sum;j++) {
for (k=0;k<=a[i]&&k<=j;k++) {
if (dp[i-1][j-k]==-1) continue;
if (k*c[i]>dp[i-1][j-k]) continue;
dp[i][j]=max(dp[i][j],dp[i-1][j-k]-k*c[i]);
}
if (dp[i][j]!=-1) dp[i][j]=min(dp[i][j]+x,cap);
cap+=b;
}
}
ll ans=0;
for (i=0;i<=sum;i++)
if (dp[n][i]!=-1) ans=i;
printf("%I64d\n",ans);
return 0;
}