2019 CCPC秦皇岛 K.MUV LUV UNLIMITED(博弈)

2019CCPC秦皇岛K

题意: 两个人玩游戏, 有一棵有根树,每次只能拿叶子节点若干个(不能不拿),问最后谁会赢

思路:

先说结论,数每个叶子节点对应上去的那条链(直到他的父亲除自己外有另外的儿子结束)的节点个数(称为树枝),如果存在奇数,则先手必胜,否则,先手必败。

简单证明一下

首先,如果树枝的节点个数为1,那么如果我拿掉这个节点之后是必败态,我就可以直接拿掉这个节点,使对手进入必败态。如果是必胜态,那就说明先手可以通过拿一些节点到达必败态,则我现在就可以拿掉那些节点,然后多拿这个节点,则现在的局面一定是必败态。

综上,如果存在树枝节点个数为1的,那么先手必胜。

1可以推广到奇数,即:先手可以把所有节点个数为奇数的树枝的叶子节点拿掉,使它变成偶数,这样对手只能把一些偶数给破坏掉,然后我一直把奇数变成偶数,这样就可以熬到对手把某个树枝的节点个数变成1,就变成了上一个状态,先手就必胜了。

代码:

#include<bits/stdc++.h>
#define endl "\n"
// #define int long long
// #define x first
// #define y second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;

const int N = 1e6 + 10, mod = 1e9 + 7, inf = 1e18;
const double eps = 1e-9, pi = acos(-1);

int n, m;
vector<int> g[N];
int fa[N];

int dfs(int u, int pre){
    bool flag = 1;
    for(int i = 0; i < g[u].size(); i ++){
        int j = g[u][i];
        if(j == pre) continue;
        fa[j] = u;
        flag = 0;
        if(dfs(j, u)) return 1;
    }
    if(flag){
        int p = u;
        int cnt = 1;
        while(p != 1){
            p = fa[p], cnt ++;
            if(g[p].size() > 1){
                if(cnt & 1) return 0;
                else return 1;
            }
        }
        if(p == 1) return cnt & 1;
    }
    return 0;
}

void solve()
{
    cin >> n;
    for(int i = 1; i <= n; i ++) g[i].clear(), fa[i] = 0;
    for(int i = 2; i <= n; i ++){
        int x;
        cin >> x;
        g[x].push_back(i);
    }
    cout << (dfs(1, -1) ? "Takeru\n" : "Meiya\n");
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int T = 1;
    cin >> T;   
    while(T -- ) solve();
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值