CodeForces922E DP//多重背包的二进制优化
Posted hugh-locke
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces922E DP//多重背包的二进制优化相关的知识,希望对你有一定的参考价值。
https://cn.vjudge.net/problem/1365218/origin
题意 一条直线上有n棵树 每棵树上有ci只鸟 在一棵树底下召唤一只鸟的魔法代价是costi 每召唤一只鸟,魔法上限会增加B 从一棵树走到另一棵树,会增加魔法X 一开始的魔法和魔法上限都是W 问最多能够召唤的鸟的个数
显然这是一道DP题
用dp[i][j]来表示到j这个树下选到j只鸟可以获得的最大能量值
很容易得出dp状态转移方程dp[i][j] = max(dp[i][j],dp[i][j - 1] - cost,dp[i - 1][j - 1] - cost);
由于每棵树上的鸟数量有限制,需要多一重大小为c的循环,但是因为∑c为1e3,三重循环的时间复杂度事实上仅为O(n * sum(c))可以接受
初始状态是dp[i][0] = W; 其他的状态为-1表示无法到达
进而可以考虑到每棵树事实上是一个多重背包,在dp的过程中考虑二进制优化,以及将dp开成滚动数组来优化空间
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Scl(x) scanf("%lld",&x); #define Pri(x) printf("%d ", x) #define Prl(x) printf("%lld ",x); #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; const double eps = 1e-9; const int maxn = 1e3 + 10; const int maxm = 1e4 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,tmp,K; LL W,B,X; LL dp[2][maxm]; PIL b[maxn]; vector<PIL>P; int C[maxn]; int main() { scanf("%d%lld%lld%lld",&N,&W,&B,&X); int sum = 0; Mem(dp,-1); For(i,1,N) Sca(C[i]); For(i,1,N){ Mem(dp[i & 1],-1); dp[i & 1][0] = W; int c = C[i]; LL cost; scanf("%lld",&cost); P.clear(); P.pb(mp(0,0)); sum += c; //cout << sum <<endl; tmp = 0; for(int j = 1; j <= c; j <<= 1){ P.pb(mp(j,cost * j)); c -= j; } if(c) P.pb(mp(c,cost * c)); for(int k = 0 ; k < P.size(); k ++){ PIL u = P[k]; for(int j = sum;j >= u.fi ; j--){ if(dp[i & 1][j - u.fi] >= u.se) dp[i & 1][j] = max(dp[i & 1][j],dp[i & 1][j - u.fi] - u.se); if(dp[i - 1 & 1][j - u.fi] == -1) continue; LL t = min(dp[i - 1 & 1][j - u.fi] + X,W + B * (j - u.fi)); if(t >= u.se) dp[i & 1][j] = max(dp[i & 1][j],t - u.se); } } } int ans; _For(i,sum,0){ if(dp[N & 1][i] != -1){ ans = i; break; } } Pri(ans); return 0; }
以上是关于CodeForces922E DP//多重背包的二进制优化的主要内容,如果未能解决你的问题,请参考以下文章