博弈论 Codeforces1215D Ticket Game

题目链接: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\n");
        else printf("Monocarp\n");
        return 0;
    }
    if(sum1<sum2){
        int res=sum2-sum1,num=(tot1-tot2)/2;
        if(num*9==res)printf("Bicarp\n");
        else printf("Monocarp\n");
        return 0;
    }
    if(sum1>sum2){
        int res=sum1-sum2,num=(tot2-tot1)/2;
        if(num*9==res)printf("Bicarp\n");
        else printf("Monocarp\n");
        return 0;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/qingjiuling/p/11535957.html