题目链接:https://www.luogu.org/problem/CF1215D
题意:一个数字序列由n(n为整数且小于2e5)位组成,其中有整数个数位被污染,现在A和B可以轮流给被污染数位赋值(0-9),A先来,若最后序列前后两端数位和不等,A赢,否则B赢,两方都选最优策略。
分析:先是高级做法
设L为左半边减右半部最小情况(左边污染部分全赋为0,右边全赋为9),R为左半边减右半边最大情况
若(L+R)/2=0,则B赢,否则就是A赢。
证明:若没有污染部分,则显然(L+R)/2=0,就是B赢,否则就是A赢。
若有污染部分,第一个玩家开始执行操作后,每次操作都会使L的值变为L~L+9之间(左边污染部分设为0或右边设为9不变,左边设为9或右边设为0变成L+9)。注:L变后会也会对应的改变R,总体的改变是每次操作使R-L减少9.如果(L+R)>0,第一个玩家肯定会选择继续增大L,将L变为L+9,之后的第二个玩家为了消除影响,会把R变为R-9,但这永远都只是消除影响,回到初始状态,赢不了,(L+R)<0时候的情况也一样。
核心就是:第一个选手把局势破坏,而第二个选手只能填前一个的坑,永远无法改变局势,既然局势一开始赢不了,那就永远赢不了。
但比赛的时候很难想这么深,有一个简单点的想法:
首先如果初始左右相对,那只有左右两边污染个数相同,B才能赢
如果初始不同的话,最后就是先把左右两边个数少的那一位消耗完(肯定是A破坏,B还原,最后某一方消耗完后左右差值和初始一样),然后集中到左右一方里。
接下来的情况就是在剩下的一方里(假设此时还剩n个污染部位),还是A先手,两方每次选择一个0~9之间的数,如果最后选择数的和等于初始左右差值,B赢,否则A赢
这就转换为一个经典博弈问题了,只要n/2*9==差值,B赢,否则A赢。
想想为什么,因为后手的B只可以控制他和A选择的数的总和是9,故如果轮数乘9和差值相等就赢,否则就输。
详细看代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=1e9+7; const int maxn=2e5+7; char s[maxn]; int tot1,tot2; int main(){ int n;scanf("%d",&n); scanf("%s",s+1); int sum1=0,sum2=0; for(int i=1;i<=n/2;i++){ if(s[i]!='?')sum1+=s[i]-'0'; else tot1++; } for(int i=n/2+1;i<=n;i++){ if(s[i]!='?')sum2+=s[i]-'0'; else tot2++; } if(sum1==sum2){ if(tot1==tot2) printf("Bicarp "); else printf("Monocarp "); return 0; } if(sum1<sum2){ int res=sum2-sum1,num=(tot1-tot2)/2; if(num*9==res)printf("Bicarp "); else printf("Monocarp "); return 0; } if(sum1>sum2){ int res=sum1-sum2,num=(tot2-tot1)/2; if(num*9==res)printf("Bicarp "); else printf("Monocarp "); return 0; } return 0; }