CodeCraft-21 and Codeforces Round 711 (Div. 2) F. Christmas Game【阶梯博弈、换根 DP】

这道题目是比较经典的树上阶梯博弈。

设一个点的深度是\(dep_i\),如果两个点\(i,j\)满足\(dep_i\not\equiv dep_j \mod k\),则两个点对答案的影响是完全独立的。

我们可以把图拆分为\(k\)部分,并且按照原图中的祖先关系把新图连接为\(k\)棵树。对于一个点\(i\),在新图中的深度为\(dep_i'=\left \lfloor \frac{dep_i}{k}\right\rfloor\)。考虑只有当\(dep_i'\)为奇数时才会对答案有影响。对于任意偶数深度的点,如果先手把他移动到偶数深度,后手一定可以通过一步操作把他重新移动到偶数深度。这一步的思考过程就是阶梯博弈。

我们可以通过DFS求出一个点做根的解,但是本题要求的是每一个点做根。对于这类题目考虑换根 DP。

\(f[i][j][l]\),表示以\(i\)为子树,\(j \equiv dep \mod k, l \equiv \left\lfloor \frac{dep'}{l} \right\rfloor \mod 2\),然后进行换根 DP。换根的时候,只有当\(j=k-1\)时,\(l\)才会发生变化。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int, int>;

const i32 inf = INT_MAX / 2;

const int mod = 1e9 + 7;

vi a;
vector<vi> e;
vector<vector<vi>> g;
int k;

void dfs(int x, int fa) {
    g[x][0][0] = a[x];
    for (auto y: e[x]) {
        if (y == fa)continue;
        dfs(y, x);
        for (int j = 0; j < k; j++)
            for (int l = 0; l < 2; l++) {
                int nj = j, nl = l;
                nj++;
                if (nj == k) nj = 0, nl ^= 1;
                g[x][nj][nl] ^= g[y][j][l];
            }
    }
    return;
}

void dp(int x, int fa) {
    if (x != 1) {
        auto tmp = g[fa];
        for (int j = 0; j < k; j++) {
            for (int l = 0; l < 2; l++) {
                int nj = j + 1, nl = l;
                if (nj == k) nj = 0, nl ^= 1;
                tmp[nj][nl] ^= g[x][j][l];
            }
        }
        for (int j = 0; j < k; j++)
            for (int l = 0; l < 2; l++) {
                int nj = j + 1, nl = l;
                if (nj == k) nj = 0, nl ^= 1;
                g[x][nj][nl] ^= tmp[j][l];
            }
    }
    for (auto y: e[x]) {
        if (y == fa) continue;
        dp(y, x);
    }
    return;
}

i32 main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int n;
    cin >> n >> k;

    e = vector<vi>(n + 1);
    for (int i = 1, x, y; i < n; i++) {
        cin >> x >> y;
        e[x].push_back(y);
        e[y].push_back(x);
    }

    a = vi(n + 1);
    for (int i = 1; i <= n; i++) cin >> a[i];

    g = vector(n + 1, vector(k, vi(2)));
    dfs(1, -1), dp(1, -1);

    for (int i = 1, sg; i <= n; i++) {
        sg = 0;
        for (int j = 0; j < k; j++) sg ^= g[i][j][1];
        cout << (sg != 0) << " ";
    }

    return 0;
}

posted @ 2024-11-14 16:11  PHarr  阅读(9)  评论(0编辑  收藏  举报