CodeForces - 922E Birds

Solution

首先是常规写法: f [ i ] [ j ] f[i][j] f[i][j] 表示走到第 i i i 棵树,如今魔法值为 j j j 能召唤最多的小鸟数。但这面临两个问题:

  • 魔法值太大。
  • 还有一个魔法上限的限制无法操作,因为上限还和召唤鸟的个数有关。

看到 ∑ c [ i ] ≤ 1 0 4 \sum c[i]\le 10^4 c[i]104自然想到将其作为 D P \mathtt{DP} DP 的一个状态,其实更正确的思路是发现魔法值和上限都与小鸟数有关。

考虑 f [ i ] [ j ] f[i][j] f[i][j] 表示走到第 i i i 棵树,如今召唤 j j j 只小鸟剩下最多的魔法值(上限可以直接根据 i , j i,j i,j 推出),然后利用魔法值是否为非负判断最多召唤的小鸟。

和一般的多重背包不一样的是,这里的 j , k j,k j,k 都要取到 0 0 0,因为每走一棵树魔法值都会变。

Code

#include 
#include 
#include 
using namespace std;
typedef long long ll;

const int N = 1e3 + 5, MAXC = 1e4 + 5;

int n, W, B, X, c[N], Cost[N], lim, ans;
ll f[MAXC];

int read() {
	int x = 0, f = 1; char s;
	while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
	while(s >= '0' && s <= '9') x = (x << 1) + (x << 3) + (s ^ 48), s = getchar();
	return x * f;
}

int main() {
	n = read(), W = read(), B = read(), X = read();
	for(int i = 1; i <= n; ++ i) c[i] = read(), lim += c[i];
	for(int i = 1; i <= n; ++ i) Cost[i] = read();
	memset(f, -1, sizeof f); f[0] = W;
	for(int i = 1; i <= n; ++ i) {
		for(int j = lim; ~j; -- j)
			for(int k = 0; k <= min(j, c[i]); ++ k) {
				if(f[j - k] == -1) continue;
				ll magic = min(f[j - k] + X, 1ll * (j - k) * B + W) - 1ll * Cost[i] * k;
				if(magic < 0) continue;
				f[j] = max(f[j], min(magic, 1ll * j * B + W));
				ans = max(ans, j);
			}
	}
	printf("%d\n", ans);
	return 0;
}

你可能感兴趣的:(#,你的背包~)