2022 CCPC 绵阳区域赛 A
A - Ban or Pick, What's the Trick
博弈论 dp。
设 \(dp_{i,j,k}\) 表示第 \(i\) 轮 A 选了 \(j\) 个,B 选了 \(k\) 个。
对 A 来说,当前如果要选应该选第 \(i - k + j + 1\) 个位置, \(i - k\) 为对手 ban 掉的,\(j\) 为自己已经选的,同理,B 要选也是第 \(i - j + k + 1\) 个,但这里是把 \(i\) 拆成 \(2n\) 轮了,所以对于 A 来说,这一轮里 B 要选的位置就是 A 可以选择 ban 掉的位置。
A 要取最大化,B 要最小化,注意取 dp 值时的比较。
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
constexpr int N = 1E5 + 10;
int dp[2 * N][11][11];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<int> a(n + 1), b(n + 1);
for (int i = 1; i <= n; i += 1) {
cin >> a[i];
}
for (int i = 1; i <= n; i += 1) {
cin >> b[i];
}
sort(a.begin() + 1, a.end(), greater<>());
sort(b.begin() + 1, b.end(), greater<>());
const int inf = 2E9;
for (int i = 1; i <= 2 * n; i += 1) {
for (int j = 0; j <= m; j += 1) {
for (int k = 0; k <= m; k += 1) {
dp[i][j][k] = (i % 2 ? 1 : -1) * inf;
}
}
}
auto dfs = [&](auto &&self, int i, int j, int k)->int{
if (i > 2 * n) {
return 0;
}
if (dp[i][j][k] != inf && dp[i][j][k] != -inf) {
return dp[i][j][k];
}
int posa = i / 2 - k + j + 1;
int posb = i / 2 - j + k + 1;
int ans;
if (i & 1) {
ans = -inf;
if (posa <= n && j != m) {
ans = max(ans, self(self, i + 1, j + 1, k) + a[posa]);
}
ans = max(ans, self(self, i + 1, j, k));
}
else{
ans = inf;
if (posb <= n && k != m) {
ans = min(ans, self(self, i + 1, j, k + 1) - b[posb]);
}
ans = min(ans, self(self, i + 1, j, k));
}
return dp[i][j][k] = ans;
};
cout << dfs(dfs, 1, 0, 0) << "\n";
return 0;
}

浙公网安备 33010602011771号