B2. Palindrome Game (hard version)

原题链接:Problem - B2 - Codeforces

题意:对一个01回文串,每次有两个操作

(1)将一个0变为1,消耗1美元;

(2)将字符串翻转,不消耗金钱,但只有在非回文情况下才可做该操作,且上家做完该操作后下家不可做同样的跟进。当串全为1时游戏结束,花钱少的人胜,问给定串后先后手是否存在必胜策略。

思路:

初始字符串分成了回文与非回文两种情况:

      一、当初始字符串为回文时:

(1)当字符串长度为偶数时或当字符串长度为奇数并且字符串中间为1时或0的个数为1时:

    此时Bob必胜。因为Alice先手,并且此时字符串为回文,所以刚开始Alice只能选择将0变1的操作,之后若剩下的0的个数大于1,Bob则也可以进行一个将0变1的操作,将字符串变回文,这样重复下去直到轮到Bob时0的个数为1个了,Bob进行翻转操作,Alice下一步也就是游戏的最后一步,Alice只能选择将0变1。最后看得出Alice永远比Bob多走两步,当字符串长度为偶数时Bob必胜。

 (2)当字符串长度为奇数并且字符串中间为0时:

  Alice的第一步可以先选择将中间的0变成1,这样选择了之后字符串仍是回文串,主动权就到了Alice身上,Alice可以重复字符串长度为偶数时Bob的操作,从而达到必胜的目的。当然,要特判一下0的个数为1的情况,此时Bob后手必胜。

       二、当初始字符串为非回文时:

此时的主动权在Alice手上,绝大部分情况下Alice必胜,还有一种情况是除了正中间的0(字符串长度为奇数)以外只有一个0了,此时达成平局。

void solve() {
	string s;
	int n, cnt = 0, flag = 0;
	cin >> n;
	cin >> s;
	FOR(0, n - 1) cnt += s[i] == '0';
	for (int i = 0, j = n - 1; i < j; i++, j--) flag += s[i] != s[j];
	if (!flag) {
		if (cnt == 1) cout << "BOB" << endl;
		else if (s[n / 2] == '0' && cnt % 2) cout << "ALICE" << endl;
		else cout << "BOB" << endl;
	} 
	else {
		if (s[n / 2] == '0' && cnt == 2 && n % 2) cout << "DRAW" << endl;
		else cout << "ALICE" << endl;
	}
}

你可能感兴趣的:(codeforces题解,算法)