[USACO22DEC] Bribing Friends G
题意
给定 \(N\) 个物品,第 \(i\) 个物品的价值为 \(P_i\),重量为 \(C_i\),第 \(i\) 个物品每花费 \(X_i\) 元,可使其重量减 \(1\)。重量不能减少至负数。现在有 \(A\) 容量的背包和 \(B\) 元,试求能够装下的物品的最大的价值。
数据范围:\(1\le N,P_i,C_i,X_i,A,B\le 2\times 10^3\)。
思路
容易发现(我没发现),由于都是使重量减 \(1\),那肯定花费越小的越好,即使劲用 \(X_i\) 小的,用完再用次小的,以此类推。
那么,所有选择物品中,按 \(X_i\) 从小到大排序,前缀必然是全部花费 \(X_i\) 元,使得重量为 \(0\),花费 \(C_iX_i\) 元;后缀必然是使用 \(C_i\) 的重量装填。中间一个物品使用一部分。故,预处理前缀、预处理后缀、中间的物品暴力枚举即可。
时间复杂度 \(O(N\max(A,B))\)。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2005;
int N, A, B;
struct info {
int P, C, X;
bool operator< (const info &T)const {
return X < T.X;
}
}F[maxn];
int f[maxn][maxn], g[maxn][maxn];
int main() {
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
cin >> N >> A >> B;
for (int i = 1; i <= N; i ++)
cin >> F[i].P >> F[i].C >> F[i].X;
sort(F + 1, F + 1 + N);
memset(f, -0x3f, sizeof f);
for (int i = 0; i <= B; i ++)
f[0][i] = 0;
for (int i = 1; i <= N; i ++)
for (int j = 0; j <= B; j ++) {
f[i][j] = f[i - 1][j];
if (j >= F[i].C * F[i].X)
f[i][j] = max(f[i - 1][j - F[i].C * F[i].X] + F[i].P, f[i][j]);
}
memset(g, -0x3f, sizeof g);
for (int i = 0; i <= A; i ++) g[N + 1][i] = 0;
for (int i = N; i >= 1; i --)
for (int j = 0; j <= A; j ++) {
g[i][j] = g[i + 1][j];
if (j >= F[i].C)
g[i][j] = max(g[i + 1][j - F[i].C] + F[i].P, g[i][j]);
}
int res = -(1 << 30);
for (int i = 1; i <= N; i ++)
for (int j = 0; j <= F[i].C; j ++) {
int _A = j, _B = (F[i].C - j) * F[i].X;
if (_B > B) continue;
res = max(res, f[i - 1][B - _B] + g[i + 1][A - _A] + F[i].P);
}
cout << res << endl;
return 0;
}

浙公网安备 33010602011771号