D. Iris and Game on the Tree

有明显结论,值为 \(0\) 当且仅当经过的序列去掉无用的之后是一个回文串。

此时,只有 \(0,1\) 相间的部分才是有用的。

\(10010\) trans to \(1010\)

那么回文就变成了根节点和叶子节点的值一样。

于是可以得出既不是根节点也不是叶子节点的部分是完全无用的,因为它不会改变任何一个叶子的值。

如果根固定,两个人按照自己目标把叶节点未知的决定为与根节点相同或者不同就行了。

如果根不固定,并且叶节点两个值的数量不同,那么先手肯定选择将根决定成为与最多的叶子节点不同的值,这样容易证明绝对最优。然后按照上一问处理即可。

如果数量不同,情况就变成了,如果哪个人去决定根或者叶子的值,那么它就会变成第一种情况的后手,这显然不是很好。所以先手可以考虑去决定无关的点,这样如果无关的点是奇数个,先手就变成另一个人,并且他必须决定根或者叶子的任意一个从而变成后手。

好的,我们讨论完了,那么做法就显而易见了。代码很好写。

// Problem: D. Iris and Game on the Tree
// Contest: Codeforces - Codeforces Round 969 (Div. 2)
// URL: https://codeforces.com/contest/2007/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define int long long
#define upp(a, x, y) for (int a = x; a <= y; a++)
#define dww(a, x, y) for (int a = x; a >= y; a--)
#define pb(x) push_back(x)
#define endl '\n'
#define x first
#define y second
#define PII pair<int, int>
using namespace std;
const int N = 2e5 + 10;
int h[N], ne[N], e[N], n, idx;
int color[N];
char a[N];
void add(int a, int b) {
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
}
void dfs(int u, int fa) {
    int flag = 1;
    for (int i = h[u]; i != -1; i = ne[i]) {
        int j = e[i];
        if (j == fa) continue;
        flag = 0;
        dfs(j, u);
    }
    if (u == 1)
        color[u] = 1;
    else if (flag) {
        color[u] = 3;
    } else
        color[u] = 2;
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int tt;
    cin >> tt;
    memset(h, -1, sizeof h);
    while (tt--) {
        upp(i, 0, n) h[i] = -1;
        idx = 0;
        cin >> n;
        upp(i, 1, n - 1) {
            int x, y;
            cin >> x >> y;
            add(x, y);
            add(y, x);
        }
        upp(i, 1, n) cin >> a[i];
        dfs(1, -1);
        int sum1 = 0, sum2 = 0, cnt1 = 0; //叶子节点 无关节点
        int ans = 0;
        bool flag = 1;
        upp(i, 1, n) {
            if (color[i] == 3) ans++;
            if (a[i] == '?') {
                if (color[i] == 1)
                    flag = 0;
                else if (color[i] == 2)
                    sum2++;
                else
                    sum1++;
            } else if (color[i] == 3)
                if (a[i] != a[1] && a[1] != '?') cnt1++;
        }
        if (flag)
            cout << cnt1 + (sum1 + 1) / 2 << endl;
        else {
            int cnt2 = 0, cnt3 = 0; // 等于 1,等于 2
            upp(i, 1, n) if (color[i] == 3) cnt2 += (a[i] == '1'),
                cnt3 += (a[i] == '0');
            if (cnt2 == cnt3) {
                if (sum2 % 2)
                    cout << (cnt2 + (sum1 + 1) / 2) << endl;
                else
                    cout << (cnt2 + (sum1) / 2) << endl;
            } else
                cout << (max(cnt2, cnt3) + (sum1) / 2) << endl;
        }
    }
    return 0;
}
posted @ 2025-03-07 14:11  PM_pro  阅读(14)  评论(0)    收藏  举报