原题传送门
这是一道背包问题
d p i dp_i dpi表示共打了 i i i只鸟剩余最大魔法值
每次走一棵树,所有 d p dp dp值 + X +X +X
每次把鸟看成物品,二进制拆分做01背包
Code:
#include <bits/stdc++.h>
#define maxn 1010
#define maxm 10010
#define LL long long
using namespace std;
LL W, B, X, cost[maxn], power[25], c[maxn], dp[maxm], sum;
int n;
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
int main(){
n = read(), W = read(), B = read(), X = read();
for (int i = 1; i <= n; ++i) c[i] = read();
for (int i = 1; i <= n; ++i) cost[i] = read();
for (int i = 0; i <= 10000; ++i) dp[i] = -1;
dp[0] = W;
power[0] = 1;
for (int i = 1; i <= 20; ++i) power[i] = power[i - 1] << 1;
for (int i = 1; i <= n; ++i){
sum += c[i];
for (int j = 0; j <= sum; ++j)
if (dp[j] != -1) dp[j] = min(dp[j] + X, W + 1LL * B * j);
for (int j = 0; j <= 14; ++j)
if (c[i] >= power[j]){
c[i] -= power[j];
for (int k = sum; k >= power[j]; --k){
if (dp[k - power[j]] == -1) continue;
if (dp[k - power[j]] - power[j] * cost[i] < 0) continue;
dp[k] = max(dp[k], dp[k - power[j]] - power[j] * cost[i]);
}
}
if (c[i])
for (int k = sum; k >= c[i]; --k){
if (dp[k - c[i]] == -1) continue;
if (dp[k - c[i]] - c[i] * cost[i] < 0) continue;
dp[k] = max(dp[k], dp[k - c[i]] - c[i] * cost[i]);
}
}
for (int i = sum; i >= 0; --i)
if (dp[i] != -1){
printf("%d\n", i); break; }
return 0;
}