题意
给定一个字符串,A和B轮流操作,A是先手;
每个人可以有如下的两种操作:
(1:)将字符串中某个位置的(0)换成(1),代价为(1)
(2:)将整个字符串翻转,代价为(0)
其中操作(2)的条件为:当前的字符串不是回文字符串并且上一次并没有执行过该操作
当字符串变为全(1)字符串时,游戏结束。代价小的获胜。
思路
先考虑(easy)版本,也就是开始都是回文字符串时,输赢跟(0)的个数有关:
- 如果当前有奇数个(0)时,由于是回文字符串,中心轴的位置一定为(0),假设为(0000000)
为了方便计算代价,假设先手改变的(1)用(2)来表示,后手改变的(1)用(3)来表示
先手会将中心轴位置的(0)变为(1),这样先手代价为(1),字符串变为(0002000)
由于当前字符串仍旧满足回文串,所以后手只能选择操作(1),后手代价为(1),字符串变为(0032000)
接下来的操作中,先手都在跟后手对称的位置进行操作(1),这样每次后手操作时,字符串都为回文串,所以只能执行操作(1)
当字符串变为(3332220)时,轮到先手操作,先手可以执行操作(2),这样字符串变为(0222333),后手只能再执行操作(1),字符串变为(3222333),最后先手的代价为(3),后手的代价为(4),先手赢。 - 如果当前有偶数个(0)时,假设为(000000)
先手只能执行操作(1),字符串变为(002000);后手也在对称的位置执行操作(1),这样类似于上一种情况,先手永远不会遇到回文串的情况,也就无法执行操作(2)
当字符串变为(322330)时,后手翻转字符串,得到(033223),先手执行操作(1),得到(233222),最后先手的代价为(4),后手的代价为(2),后手赢。 - 但是当只有1个0时,先手只能进行操作(1),后手赢。
(hard)版本如何考虑呢。
首先我们可以知道将原串变为回文串的代价,记作(sum)
- 如果(sum>=2)的话,先手必赢:假设字符串为(111000),由于字符串不是回文字符串,所以先手可以先执行操作(2),后手只能执行操作(1),直到游戏结束。
- 如果(sum==0)的话,就按照回文串的情况写
- 如果(sum==1)的话,考虑0的个数:如果只有2个0的话是平局,否则就是先手赢。
如果只有两个0说明中心轴一定为0,假设字符串为100,那么先手可以执行操作2,变为001,后手只能执行操作1,变为021,先手执行操作1,变为321,是平局;
否则的话,1101,先手执行操作2,后手执行操作1,先手代价小,先手赢。
代码
const int maxn =1e5+7;
char s[maxn];
void solve(){
int n=read;
cin>>s+1;
int cnt=0,sum=0;
for(int i=1;i<=n;i++)
if(s[i]=='0') cnt++;
for(int i=1;i<=n;i++)
if(s[i]=='1'&&s[n-i+1]=='0') sum++;
///cout<<sum<<" "<<cnt<<endl;
if(sum==0){
if(cnt==1){
cout<<"BOB"<<endl;
}
else if(cnt%2){
cout<<"ALICE"<<endl;
}
else puts("BOB");
}
else if(sum>=2){
puts("ALICE");
}
else if(sum==1){
if(cnt==2) puts("DRAW");
else puts("ALICE");
}
}
int main() {
int T=read;
while(T--){
solve();
}
return 0;
}