CF1215D Ticket Game
题目链接http://codeforces.com/problemset/problem/1215/D
分析
这道题算是一道比较水的博弈论?不知道为啥我写了一个很清奇的思路。。。。
首先数据中的给出的一串字符串没必要都存,只保存两边分别的?数量和总的数字和。
最简单的就是样例一的情况,如果没有问号,显然在这种情况下只有两边的数字和\(cnt\)初始不等时,才会有\(Monocarp\)赢,这种情况非常特殊,那能不能推广到一般呢?这里用到我xjb推出的一个结论,左边的?和右边的?是等价的。为什么呢?如果\(Monocarp\)从\(cnt\)大的一边来填数,它肯定要去拉大差距,即填9,那另一边的\(Bicarp\)为了缩小差距也会填9,当\(Monocarp\)从小的那边开始填也是一样,也就是说假如左边有5个?,右边有3个,就等价于左边有2个?。于是样例一的情况推广到当两边的?数量相同时,如果\(cnt\)不等,则\(Monocarp\)赢。
接下来考虑不等的情况。根据上边的结论,我们可以把两侧的博弈转换成一侧的博弈。
假设剩下一侧的等价问号数量为\(w\),举个例子,若\(w\)为4,则\(Bicarp\)操作次数为2,若为5,他还是操作2次,因为\(Monocarp\)会先手。
下面来考虑等价的问号在哪一侧,这里以在左边为例,假设左边的数字和为\(cnt1\)右边的为\(cnt2\),如果\(cnt1\)最开始就大于\(cnt2\)那么很抱歉\(Bicarp\)不可能赢,因为\(Monocarp\)可以一直填9,对于剩下的情况,可以只考虑极限情况,因为中间的博弈过程两个人都是选最优操作,因此可以不用考虑,极限的情况有两种,一是\(Monocarp\)疯狂填9,另外一个拦都拦不住只能填0,填到最后\(cnt1\)大于\(cnt2\)了,二是\(Bicarp\)疯狂填9,另一个一直填0,然而填到最后也达不到\(cnt2\),这两种情况都是\(Monocarp\)赢,剩下的就只需要判断了。
#include<cstdio>
const int N=2e5+10;
char s[N];
int main(){
int cnt1,cnt2,w1,w2;
int n;
cnt1=cnt2=w1=w2=0;
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<=n;i++){
if(i<=n>>1){
if(s[i]=='?')w1++;
else cnt1+=s[i]-'0';
}else {
if(s[i]=='?')w2++;
else cnt2+=s[i]-'0';
}
}
bool flag=1;
if(w1==w2){
if(cnt1!=cnt2)flag=0;
}
else if(w1>w2){
int w=w1-w2;w>>=1;
if(cnt1>cnt2)flag=0;
else if(cnt1+w*9<cnt2 || cnt1+(w1-w2-w)*9>cnt2)flag=0;//Monocarp的操作次数可能比w大1.
}else {
int w=w2-w1;w>>=1;
if(cnt2>cnt1)flag=0;
else if(cnt2+w*9<cnt1 || cnt2+(w2-w1-w)*9>cnt1)flag=0;
}
if(flag)printf("Bicarp\n");
else printf("Monocarp\n");
}
最后
因为是自己写的所以可能有Bug,如果有hack数据可以找我~