CF154D题解

不用 SG 函数的博弈论,你值得拥有。

似乎题解都写的很粗略,我来篇详细点的。

前置芝士:Bash博弈

我们先观察题目所给的条件,为两个点和转移区间。

注意到 $x$ 并不严格小于 $y$,在这种情况下将 $x$ 和 $y$ 交换一下,$a$ 和 $b$ 交换后取反即可。

现在 $x$ 严格小于 $y$ 了,发现可以划分成以下三种情况:

  • $a$ 和 $b$ 都是负数

显然是平局,原因不用我多说了吧。

  • $a$ 和 $b$ 都是正数

此时这个问题可转化为有一堆个数为 $y-x$ 个的石子,双方轮流取,至少取 $a$ 个,至多取 $b$ 个,先取完者胜。

显然是 Bash 博弈的变种。

我们用 Bash 博弈的套路去思考:

下面用 $n$ 替代 $y-x$,用 $m$ 替代 $a+b$。

如果 $n \bmod m \equiv0 $,则后手必胜;

否则分成两种情况:

  1. $x \le n \bmod m \le y$,显然先手取 $n \bmod m$ 必胜;

  2. $0<n \bmod m < x$ 或 $y < n \bmod m $,可以发现一定可以不移到第一种区间内。先手一定不必胜,因为无论先手怎么走,后手都可以粘着先手将 $m$ 补满以形成平局;后手也一定不必胜,反证法,假设后手必胜,则先手必败,根据策梅洛定理,先手转移的所有状态都必定是必胜态,而显然不转移到第二种区间内时并不转移到必胜态,矛盾。则在此情况下只能是平局。

  • $a$ 是负数,$b$ 是非负数

如果一步能挤掉就直接一步挤掉。

否则显然必定是和局。证明就不贴了。

为什么不加多测呢

code

#include <bits/stdc++.h>
using namespace std;
int n,i,j,k,m;
int a,b,x,y;
int main() {
    scanf("%d%d%d%d",&x,&y,&a,&b);

    bool flag=false;
    if(x>y){
        swap(x,y);
        swap(a,b);
        a=-a;
        b=-b;
        flag=true;
    }
    if(a<=0){
        if(x+b>=y){
            printf("FIRST\n");
            if(flag==false) printf("%d",y);
            else printf("%d",x);
        }
        else printf("DRAW");
        return 0;
    }
    int sum=y-x;
    if((sum%(a+b))==0){
        printf("SECOND");
    }
    else if(sum%(a+b)>=a && sum%(a+b)<=b){
        printf("FIRST\n");
        if(flag==true){
            printf("%d",y-sum%(a+b));
        }
        else{
            printf("%d",x+sum%(a+b));
        }
    }
    else printf("DRAW");
    return 0;
}
posted @ 2023-09-27 17:52  monster_hunterqwq  阅读(9)  评论(0编辑  收藏  举报  来源