题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1525
解题思路:
一个大数A,一个小数B,A减去了n倍B,变成了比B小的数,此时两个数的地位发生了转变。
我们把每次到达地位改变的过程称为一个状态,这个过程最多可以操作的次数为A/B
我们记录这个这个最多可以操作的次数。
最终到了什么时候可以判断胜负了呢?就是a%b==0/b%a==0,那么下一次操作的人就会获胜。
所以整个过程其实就是求gcd的过程。
我们记录求出gcd过程中每个阶段可以操作的次数。
最终就转化为了n堆石子,按顺序取,每次可以取这堆任意个(至少一个),谁取完谁就赢的问题
如果每堆都是1那没什么好说的
如果有不是大于1的,那么谁拥有第一堆>1的首次操作权,他就可以根据之后的堆,来确定当前应该留下1个还是取完来使得他能够取到下一堆大于1的堆/获胜。
代码:
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
#define for0(i,a,b) for (int i=a;i<b;i++)
#define for1(i,a,b) for (int i=a;i<=b;i++)
const int N = 100;
ll tot,a[N];
ll gcd(ll aa,ll bb)
{
if (aa<bb) swap(aa,bb);
if (aa%bb==0) return bb;
else {
a[tot++] = aa/bb;
return gcd(bb,aa%bb);
}
}
int main()
{
ll aa,bb;
while (~scanf("%lld %lld",&aa,&bb)&& !(aa==0&&bb==0)){
if (aa==0||bb==0) {puts("Ollie wins");continue;}
tot = 0;
gcd(aa,bb);
/*
for0(i,0,tot){
if (i!=0) printf(" ");
printf("%lld",a[i]);
}puts("");
*/
a[tot] = 1;
bool allone = true;
int pos = -1;
for1(i,0,tot){
if (a[i]>1) {allone = false;if (pos==-1){pos = i+1;}}
}
if ( ((tot+1)%2==1 && allone)|| (!allone && pos%2==1) ) puts("Stan wins");
else puts("Ollie wins");
}
return 0;
}