B2. Palindrome Game (hard version)-cf1527

B2. Palindrome Game (hard version)

https://codeforces.com/problemset/problem/1527/B2

题意

给定一个长度为n的二进制串
两人博弈 每次可以做下面两个操作的一个:
1.将二进制串中的一个0翻转 花费代价 1
2.如果当前字符串不是回文串且上一个人的操作不是反转字符串那就可以反转字符串 花费代价 0
最后所有字符都是1 的时候就停止游戏

思路

我们先考虑一开始是回文 对于一开始是回文就只有两个结论:
如果0的个数是偶数:
先手会多花费2
先手每次都会破坏回文串 那后手就跟着恢复回文串 到最后一次后手选择反转回文串 那先手就必须最后翻转0 可以看出先手比后手多翻转了最后的两个0
如果0的个数是奇数:
后手会多花费1
相当于先手一开翻转了最中间的一个 然后先后手互换 又变成偶数情况 后来的先手(即原来的后手)多花费了2,在加上一开始先手花费了1,相对后手多花费了1

我们用res记录到回文串要翻转0的个数res(这部分就是后手额外翻转的0的个数)
然后后面就按一开始是回文串的做
那我们就计算回文之后0的个数
如果0的个数为偶数:
如果res == 0, 那么先手肯定会都花费2
如果res != 0, 先手为了自己少花费 在最后一次要变成回文时选择翻转0,将情况转变 这样就相当于res-1,先手的花费+1,最后后手花费+2

如果0的个数为奇数:
如果0的个数是1 那么先手必须翻转0 先手的花费+1
如果0的个数大于1 那无论如何后手最后都会比先手多一次,如果在一开始变回文的过程中后手没先翻转中间的0 那么0的个数是奇数按照前面的推论后手会额外多花费1,如果先手选择先翻转中间的0 但先手不傻会在最后变成回文串的时候插一脚 转变局面 这样就又跟前面的情况是一样的 后手还是多花费1
最后比较先后手的花费即可

#include <bits/stdc++.h>
#include <stdlib.h>
using namespace std;
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
#define ll long long
#define int ll
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int N = 3e5 + 5;
const int M = 5e5 + 5;
const ll mod = 1e9 + 7;

int n;

void solve()
{
	cin >> n;
	string s;
	cin >> s;
	s = ' ' + s;

	int res = 0, cnt = 0;
	int a = 0, b = 0;
	for(int i = 1; i <= n / 2; i++){
		if(s[i] != s[n - i + 1]) {
			res++;
			s[i] = s[n - i + 1] = '1';
		}
		else if(s[i] == '0') cnt += 2;
	}

	if(n % 2 && s[(n + 1) / 2] == '0') cnt++;
	b += res;

	if(cnt && cnt % 2 == 0){
		if(!b) a += 2;
		else {
			b++;
			a++;
		}
	}
	else if(cnt % 2) {
		if(cnt == 1) a++;
		else b++;
	}

	if(a < b) cout << "ALICE\n";
	else if(a == b) cout << "DRAW\n";
	else cout <<"BOB\n";
}


signed main()
{
	IOS;
	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}
posted @ 2022-12-29 10:55  Yaqu  阅读(28)  评论(1编辑  收藏  举报