题解:P17544 [JAG 2026 Summer Camp #2] Two Greedy Customers
首先我们会有一部分物品两个人都买到。我们把这些物品扔到最前面。
而对于剩下的物品,我们会让一部分只能 A 买到,一部分只能 B 买到。对于这部分,按
考虑枚举
转移时,我们决策一个物品到底是什么情况。
- 如果它同时被两个人买到,则
f_{i, p+c, j, k} \gets f_{i-1, p, j, k} + u + v 。 - 如果它只能被 A 买到,则
f_{i, p, j+c, k} \gets f_{i, p, j, k} + u 。这里要求 B 剩下的空间b-(s+k) < c ,不然的话 B 也能买到了。 - 如果它只能被 B 买到,则
f_{i, p, j, k+c} \gets f_{i, p, j, k} + v 。这里要求 A 剩下的空间a-(s+j) < c ,不然的话 A 也能买到了。
这样直接暴力 DP 是五次方的。
这样 DP 不够优秀的主要原因是外层枚举了
考虑一开始就决定每个人分别都选了多少。重新考虑状态
初始状态是
这样转移时“剩下的空间”这个限制就可以直接被
最后对所有
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200 + 5;
int f[2][N][N][N], ans, n, a, b, c[N], u[N], v[N], q[N];
inline bool cmp(int x, int y)
{
return c[x] > c[y];
}
signed main()
{
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> a >> b;
for(int i = 1; i <= n; i++)
cin >> c[i] >> u[i] >> v[i], q[i] = i;
sort(q + 1, q + n + 1, cmp);
memset(f, -0x3f, sizeof f);
for(int s = 0; s <= min(a, b); s++)
f[0][s][a - s][b - s] = 0;
for(int i = 1; i <= n; i++)
{
int C = c[q[i]], U = u[q[i]], V = v[q[i]];
for(int p = 0; p <= min(a, b); p++)
for(int j = 0; j <= a; j++)
for(int k = 0; k <= b; k++)
f[i & 1][p][j][k] = f[(i - 1) & 1][p][j][k];
for(int p = C; p <= min(a, b); p++)
for(int j = 0; j <= a; j++)
for(int k = 0; k <= b; k++)
f[i & 1][p - C][j][k] = max(f[i & 1][p - C][j][k], f[(i - 1) & 1][p][j][k] + U + V);
for(int p = 0; p <= min(a, b); p++)
for(int j = 0; j <= a; j++)
for(int k = 0; k <= b; k++)
{
if(f[(i - 1) & 1][p][j][k] < 0) continue;
if(j >= C && k < C)
{
f[i & 1][p][j - C][k] = max(f[i & 1][p][j - C][k], f[(i - 1) & 1][p][j][k] + U);
}
if(k >= C && j < C)
{
f[i & 1][p][j][k - C] = max(f[i & 1][p][j][k - C], f[(i - 1) & 1][p][j][k] + V);
}
}
}
for(int j = 0; j <= a; j++)
for(int k = 0; k <= b; k++)
ans = max(ans, f[n & 1][0][j][k]);
cout << ans << '\n';
return 0;
}