问题链接(https://codeforces.com/problemset/problem/1215/D)
问题描述
一张票有n位数,如果这张票的前一半数字的和等于后一半数字的和(n一定是偶数),就称这张票为快乐票。有些数被擦除了,标记为’?’(’?‘的个数也是偶数),现在Monocarp 和 Bicarp 进行一个游戏,两人轮流将’?'变换成0到9的任意一个数,Monocarp先手,如果最后票为快乐票则Bicarp赢,否则Monocarp赢。
问题分析
先分别获取两部分非擦除数的和v1、v2,以及两半数中’?‘的个数cnt1、cnt2。并可以用v1、v2中大的数减小的数得到x,因问题都是对称的,所以不妨设v1>=v2,记x=v1-v2。那么问题统一为:前一半数的和为x+cnt1个’?’(值可不一,下同),后一半数的和为cnt2个’?’。
现分析以下几种情况:
若cnt1==cnt2,则M(简略表述,M代表Monocarp,B代表Bicarp)可以先对左边的’?'变9,接着无论B怎么操作,M只需要在B的操作完的那一半数的另一半数做相同的操作,就可以保证最后操作结果左边等于右边(不考虑x),也就是最后左边会比右边多一个x,所以这种情况B赢的条件是x为0,当然x为0时,B也是只需要模仿M的操作就可以使两边相等了。
若cnt1>cnt2,M在前一半不断加9,或在后一半不断加0,即使是不考虑x,B无论怎么操作也不能使两半相等。
若cnt1<cnt2,x必须等于a=9×(cnt2-cnt1)÷2,B才能让前后两半相等。如果x比a大,那么M还是可以通过在前一半加9或者后一半加0的方式让最终前一半的和比后一半的和大,因为B只能在对应的另一半加9、加0,但也无济于事。同理如果x比a小,那么M可以通过在前一半加0或者后一半加9的方式让最后前一半比后一半小。
代码如下
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
#define endl '\n'
char str[N];
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int n,cnt1,cnt2,v1,v2,v;
cin>>n>>str;
cnt1=cnt2=v1=v2=0;
for(int i=0,half=n/2;i<half;i++){
if(str[i]=='?') cnt1++;
else v1+=str[i]-'0';
}
for(int i=n/2;i<n;i++){
if(str[i]=='?') cnt2++;
else v2+=str[i]-'0';
}
if(v1<v2){
swap(v1,v2);
swap(cnt1,cnt2);
}
v=v1-v2;
if(cnt1==cnt2&&!v) cout<<"Bicarp"<<endl;
else if(cnt2>cnt1&&v==(cnt2-cnt1)/2*9) cout<<"Bicarp"<<endl;
else cout<<"Monocarp"<<endl;
return 0;
}