博弈论dp复习笔记
Stones
题目概述
集合 \(A\),小 \(X\) 和小 \(Y\) 选择其中一个数 \(x\),然后将石堆拿走 \(x\) 个,谁不能操作谁输,一开始石堆石头数量为 \(k\).
数据范围:\(1\leq k\leq 10^5,1\leq n\leq 100,1\leq a_i\leq 10^9\)。
分析
设 \(f_i\) 表示到 \(i\) 时若再进行一次操作那他是必胜还是必败。
设后继集合 \(S_i\),有:
\[f_i=[\sum_{x\in S_i}[f_x]]\geq 1
\]
然后没了。
代码
时间复杂度 \(\mathcal{O}(nk)\),代码如下:
#include <iostream>
#include <stdlib.h>
#include <cstdio>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <cstring>
#define int long long
#define N 105
#define K 100005
using namespace std;
int sg[K],n,k,a[N];
signed main(){
cin >> n >> k;
int mn = 1e18;
for (int i = 1;i <= n;i ++) scanf("%lld",&a[i]),mn = min(mn,a[i]);
stable_sort(a + 1,a + 1 + n);
for (int i = 0;i < mn;i ++) sg[i] = 0;
for (int i = mn;i <= k;i ++) {
sg[i] = 0;
for (int j = 1;j <= n && a[j] <= i;j ++)
sg[i] |= sg[i - a[j]] == 0;
}
if (sg[k]) puts("First");
else puts("Second");
return 0;
}
Deque
题目概述
一个序列 \(A\),小 \(X\) 和小 \(Y\) 从两边取数,并累积到自己的得分中,两个人都十分聪明,求最后的小 \(X\) 分数减去小 \(Y\) 分数的值。
数据范围:\(1\leq n\leq 10^3,1\leq a_i\leq 10^9\)。
分析
经典题目。
牛了,其实是区间 \(dp\)。
设 \(f_{i,j}\) 表示只在区间 \([i,j]\) 完的最大得分(相减之后)。
转移就 \(\mathcal{O}(1)\) 了。
代码
时间复杂度 \(\mathcal{O}(n^2)\)。
#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <cstring>
#include <algorithm>
#include <vector>
#define int long long
#define N 3005
using namespace std;
int n,a[N];
int f[N][N];
signed main(){
cin >> n;
for (int i = 1;i <= n;i ++) scanf("%lld",&a[i]);
for (int i = 1;i <= n;i ++) f[i][i] = a[i];
for (int len = 2;len <= n;len ++)
for (int i = 1;i + len - 1 <= n;i ++) {
int j = i + len - 1;
f[i][j] = max(a[i] - f[i + 1][j],a[j] - f[i][j - 1]);
}
cout << f[1][n];
return 0;
}

浙公网安备 33010602011771号