题解:P13018 [GESP202506 七级] 调味平衡
考场上也不知道咋写出这种做法的,反正很玄学。
思路:
一开始看到就想到动规,但是就没想到怎么表示状态,但后来看到数据这么小,就想到了一种很笨的方法。就是使用
于是转移方程就出来了,就是:
if(j <= a[i].cha) f[i][j][1] = max(f[i][j][1], f[i - 1][a[i].cha - j][0] + a[i].sum);
else f[i][j][1] = max(f[i][j][1], f[i - 1][j - a[i].cha][1] + a[i].sum); //正数情况
if(-j <= a[i].cha) f[i][j][0] = max(f[i][j][0], f[i - 1][a[i].cha + j][0] + a[i].sum);
else f[i][j][0] = max(f[i][j][0], f[i - 1][-j - a[i].cha][1] + a[i].sum); //负数情况
注意:
1、就是这个差值调了好久,数组一定要开大点,不然会越界。
2、不要忘了不选的情况,就是:
f[i][j][1] = max(f[i][j][1], f[i - 1][j][1]);
f[i][j][0] = max(f[i][j][0], f[i - 1][j][0]);
这个要先写。
完整代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e2 + 5, M = 1e5 + 5;
struct Node { int x, y, cha, sum; } a[N]; //cha 代表差值,sum 代表和
int n;
int f[N][M * 2][2]; //注意要把数组开大,防止越界
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i].x >> a[i].y, a[i].cha = a[i].x - a[i].y, a[i].sum = a[i].x + a[i].y;
memset(f, -0x3f, sizeof f);
for(int i = 1; i <= n; i++) { //初值
if(a[i].cha <= 0) f[i][-a[i].cha][0] = a[i].sum;
else f[i][a[i].cha][1] = a[i].sum;
}
for(int i = 1; i <= n; i++) {
for(int j = 0; j <= M; j++) {
f[i][j][1] = max(f[i][j][1], f[i - 1][j][1]);
if(j <= a[i].cha) f[i][j][1] = max(f[i][j][1], f[i - 1][a[i].cha - j][0] + a[i].sum);
else f[i][j][1] = max(f[i][j][1], f[i - 1][j - a[i].cha][1] + a[i].sum); //正数情况
f[i][j][0] = max(f[i][j][0], f[i - 1][j][0]);
if(-j <= a[i].cha) f[i][j][0] = max(f[i][j][0], f[i - 1][a[i].cha + j][0] + a[i].sum);
else f[i][j][0] = max(f[i][j][0], f[i - 1][-j - a[i].cha][1] + a[i].sum); //负数情况
}
}
cout << max(0LL, max(f[n][0][0], f[n][0][1])) << endl; //防止无解,要与 0 比
return 0;
}