codeforce 461DIV2 E题
题意
有n棵树排成一排,每个树上都有c[i]只小鸟,只有站在树下才可以召唤小鸟,在i-th树下召唤k(k<=c[i])只小鸟需要消耗cost[i]*k的法力值,但是每召唤一只小鸟可以将法力值的上限增加B,每次到下一棵树时候,法力值会恢复X(但是不会超过上线),初始时的法力值和上限都是W。
分析
emmm这个题我不会,但感觉真的棒!乍一看很像背包有没有!一开始我想dp[a][b]表示在状态(a,b)时捉到小鸟的最大值,(a,b)代表第a棵树,当前法力值为b,法力值的上限可以通过捉到的小鸟数得到,那么转移就很显然dp[a][b]=max(dp[a][b],dp[a-1][b+k*cost[a]-X]+k)其中b+k*cost[a]<=W+dp[a-1][b+k*cost[a]-X]*B;如果是这样这道题就是简单的背包了,但是注意数据范围!数组开不下!!!再回去认真审题(zhao ti jie),发现有一个提示是c[i]的和小于等于十的四次方,这是在暗示我们将它加入到状态中啊!于是我们就可以这样写dp;
dp[a][b]为在状态(a,b)时剩余的最大能量值,状态(a,b)代表在第a棵树下,已经抓到了b只小鸟。那么初始状态便为dp[0][0]=W;
状态转移为dp[a][b]=max(dp[a][b],min(dp[a-1][b-k]+X,W+(b-k)*B)- cost[a]*k);初始时可以将所有的dp数组赋值为-inf;最后i从大到小找dp[n][i],当它的值大于等于0的时候(或者不等于-INF),当前i就是答案
对了,这道题不用long long 的话会在第7组WA。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 const int INF=2147483600; 7 const int maxn=1000+10; 8 const int maxc=10000+10; 9 long long n,W,B,X; 10 long long c[maxn],cost[maxn]; 11 long long dp[maxn][maxc]; 12 int main(){ 13 //scanf("%d%d%d%d",&n,&W,&B,&X); 14 cin>>n>>W>>B>>X; 15 long long M=0; 16 for(int i=1;i<=n;i++){ 17 cin>>c[i]; 18 M+=c[i]; 19 } 20 for(int i=1;i<=n;i++)scanf("%d",&cost[i]); //cin>>cost[i]; 21 for(int i=0;i<=n;i++) 22 for(int j=0;j<=M;j++) 23 dp[i][j]=-INF; 24 dp[0][0]=W; 25 for(int i=1;i<=n;i++){ 26 for(int j=0;j<=M;j++){ 27 for(int k=0;k<=c[i];k++) 28 if(k<=j&&min(dp[i-1][j-k]+X,W+(j-k)*B)>=cost[i]*k) 29 dp[i][j]=max(dp[i][j],min(dp[i-1][j-k]+X,W+(j-k)*B)-cost[i]*k); 30 } 31 } 32 33 int ans=0; 34 for(int i=M;i>=0;i--){ 35 if(dp[n][i]>=0){ 36 ans=i; 37 break; 38 } 39 } 40 printf("%d",ans); 41 return 0; 42 }