Codeforces 142D(博弈)

要点

  • 不难发现问题转化成:n堆石子,每次最多选k堆最少选1堆然后拿走一个石子,谁先没子可拿谁败。本题中撤退不必考虑。
  • 就是记笔记吧,类似nim的博弈,举例:$$k=3,n=4$$$$4堆石子分别是1、2、3、3$$全化为二进制$$01$$$$10$$$$11$$$$11$$然后每一位纵向加和,两位都是(3\%(k+1)==0),全能整除((k+1))则后手胜,否则都是先手胜。PS:我只知道(k+1)应该与那个经典益智问题有关:共有若干火柴,每次最少拿1最多拿k,怎样先手必胜。
int n, m, k;
char s[105];
int ans, val[105];
bool flag1, flag2;

int main() {
	ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cin >> n >> m >> k;
	rep(i, 1, n) {
		cin >> s;

		val[i] = -1;
		int f1 = -1, f2 = -1, tmp = 0;
		rep(j ,0, m - 1)
			if (s[j] == 'G')	f1 = j;
			else if (s[j] == 'R')	f2 = j;
			else	tmp++;

		if (tmp == 0 || tmp == m)	continue;
		if (f1 >= 0 && f2 >= 0) {
			val[i] = abs(f2 - f1) - 1;
		} else if (f1 < 0) {
			flag2 = 1;
		} else	flag1 = 1;
	}
	if (!flag1 && !flag2) {
		int tmp[10] = {0};
		rep(i, 1, n)
			if (val[i] > 0) {
				int cnt = 0;
				for (int j = val[i]; j; j >>= 1)
					tmp[cnt++] += j % 2;
			}
		rep(i, 0, 9)
			if (tmp[i] % (k + 1) != 0) {
				flag1 = 1;
			}
		cout << (flag1 ? "First
" : "Second
");
	} else if (flag1 && flag2) {
		cout << "Draw
";
	} else	cout << (flag1 ? "First
" : "Second
");
	return 0;
}
原文地址:https://www.cnblogs.com/AlphaWA/p/11123888.html