把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

博弈论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;
}
posted @ 2025-10-07 20:18  high_skyy  阅读(3)  评论(0)    收藏  举报
浏览器标题切换
浏览器标题切换end