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 $,则后手必胜;
否则分成两种情况:
-
$x \le n \bmod m \le y$,显然先手取 $n \bmod m$ 必胜;
-
$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;
}