P1290 欧几里德的游戏

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1290 欧几里德的游戏相关的知识,希望对你有一定的参考价值。

P1290 欧几里德的游戏

题意:

给定两个正整数 M 和 N,从 Stan 开始,从其中较大的一个数,减去较小的数的正整数倍,当然,得到的数不能小于 0。然后是 Ollie进行同样的操作,直到一个人得到0,他就取得胜利

题解:

我们假设当前状态为(x,y),y>=x
如果y是x的倍数,先手获胜。
然后我们考虑其他情况:
假设y = kx +b,b<x
如果k>=2.说明当前状态可以转移到(x,y-(k-1)x)即(x,x+b),也就可以转移到(x,y-kx)即(x,b),而(x,x+b)也可以转移到(x,b),可得到图:
根据判定引理:(x,y)都为必胜
解释:如果(x,y)为必败,(x,x+b)为必胜,(x,y)为必胜
如果(x,y)为必胜,(x,x+b)为必败,(x,y)为必胜
在这里插入图片描述
如果k=1时,(x,y)=(x,x+b)---->(x,b),此时问题就变成了初始局面为(x,b),能否赢(注意此时原先的先手变成后手,所以递推时要转变状态)

代码:

#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
typedef long long ll;
using namespace std;

inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
   return s*w;
}
bool check(int x,int y,int p){
	if(x%y==0)return p;//返回当前胜者 
	if(y>=x*2)return p;
	else return check(y-x,x,p^1); 
}
int main()
{
	int q;
	cin>>q;
	for(int i=1;i<=q;i++){
		int n,m;
		cin>>n>>m;
		if(n<m)swap(m,n);//保证n大,m小 
		//我们认为返回0先手胜,所以一开始传的也是0 
		if(check(m,n,0)==0)cout<<"Stan wins"<<endl;
		else cout<<"Ollie wins"<<endl;
	} 
	return 0;
}

从Sg函数角度考虑

参考文章
最终情况为:一个数是x,另一个是0,此时先手必败
假设:现在n和m,n>m>0
sg(n,m)=mex{sg(n-m,m),sg(n-2m,m),…sg(m,n%m)}(此时n%m<m,说明交换了顺序,默认前者大于后者)
如何求sg()呢?
SG(n-m, m)=mex{SG(n-2m, m), SG(n-3m, m)…SG(m, n%m)}
sg(n-2m,m)也是同理
也就是说除了sg(m,n%m),此外所有的sg都可以由sg(m,n%m)得到
假设sg(m,n%m)==0,设n/m=k,k>=1,SG(n-(k-1)*m,m) == mex{SG(m, n%m)}=1,从此往上一直到SG(n, m)的值为2,3,4,5…,即一直必胜
如果sg(m,n%m) == 1,那么 SG(n-(k-1)*m,m) == mex{SG(m, n%m)}=0,剩下的依旧为1,2,3,4,5,6…
所以当n/m == 1时(即n=m+b,b<m),sg(n,m)!=sg(m,n%m),不然n和m就是1

其实和我一开始推是一样的,不过用sg函数更为正宗

#include <cstdio>
#define min(a, b) (a<b? a : b)
#define max(a, b) (a<b? b : a)
int T, m, n;
bool solve(int n, int m)
{
    if (!m)return false;
    if (n/m == 1)return !solve(m, n%m);
    else return true;
}
int main()
{
    scanf("%d", &T);
    for (int xx = 1; xx <= T; xx++)
    {
        scanf("%d%d", &n, &m);
        if (solve(max(n, m), min(n, m)))
            printf("Stan wins\\n");
        else
            printf("Ollie wins\\n");
    }
}

以上是关于P1290 欧几里德的游戏的主要内容,如果未能解决你的问题,请参考以下文章

P1290 欧几里德的游戏

P1290 欧几里德的游戏

P1290 欧几里德的游戏

洛谷P1290 欧几里德的游戏 数学 博弈论 模拟

AC日记——欧几里得的游戏 洛谷 P1290

洛谷 [P1290] 欧几里得的游戏