矿物运输「CSP多校联考 2019」

题意

在某个不知名的行星上蕴含着大量冰晶矿,(Jim)和他的好兄弟(Swan)自然不能放过这个赚钱的好机会。

(Jim)在整个星球上开掘树型矿洞,每个矿坑之间都有矿道相连。

(Jim)(Swan)在每个矿坑开采了大量的矿石,现在他们面临一个新的问题,怎么把所有的矿石运出去。已知,矿坑与矿坑之间形成了有向的树形结构,即除0号矿坑以外每个矿坑都有与其相连的父亲矿坑。(Jim)总共开采了n个矿坑并将其从0到n编号 ,每个矿坑都存有(val[i])个单位的矿石。

(Jim)(Swan)每次操作都可以从某个矿坑移动至少1个单位的矿石到其父亲矿坑。(Jim)(Swan)决定比试一下,由(Jim)开始轮流操作,最后不能操作的人输。(Jim)偷偷的找到了你,他想知道在两人都采取最优策略的情况下是否(Jim)能够赢得这场比试。


思路

博弈论题目≈你做不出来但是人人都会的题

可以把树看为很多个链,然后每一个链都是奇数位异或,所以最后相当于对深度为奇数的点值异或,如果为0就会输,否则胜利。

代码

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO {

    template<typename T>inline void read (T &x) {
        x=0;T f=1;char c=getchar();
        for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
        for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
        x*=f;
    }

    template<typename T>inline void write (T x) {
        if (x<0) putchar('-'),x*=-1;
        if (x>=10) write(x/10);
        putchar(x%10+'0');
    }

}

using namespace StandardIO;

namespace Project {
	
	const int N=300300;

	int T;
	int n,ans,fa;
	vector<int> G[N];
	int val[N];
	
	void dfs (int now,int fa,int dep) {
		if (dep&1) ans^=val[now];
		for (register int i=0; i<G[now].size(); ++i) {
			int to=G[now][i];
			if (to==fa) continue;
			dfs(to,now,dep+1);
		}
	}

	inline void MAIN () {
		read(T);
		while (T--) {
			read(n),ans=0;
			for (register int i=0; i<=n; ++i) {
				G[i].clear();
			}
			for (register int i=1; i<n; ++i) {
				read(fa);
				G[i].push_back(fa),G[fa].push_back(i);
			}
			for (register int i=0; i<n; ++i) read(val[i]);
			dfs(0,-1,0);
			if (ans) puts("win");
			else puts("lose");
		}
	}
	
}

int main () {
//    freopen("ore.in","r",stdin);
//    freopen("ore.out","w",stdout);
    Project::MAIN();
}
原文地址:https://www.cnblogs.com/ilverene/p/11820882.html