题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1525
34 12 15 24 0 0
Stan wins Ollie wins
题目意思:
两个人,两堆石头,玩游戏。每次从石头数多的那堆中拿走石头数少的那堆石头的个数的倍数个,保证拿了过后不能为负数。谁恰好使其中一堆石头数为0,谁使其中某一堆石头为0,谁赢。两人都足够聪明。
解题思路:
借助欧几里得算法的博弈。
显然如果a>b 且a>2*b 先拿者必赢 因为他可以决定是自己还是对手遇到状态(a%b,b)如果状态(a%b,b)为必输状态,他就让对手面对(拿走a-a%b个)。如果为必赢状态,他就自己面对(拿走-a%b-b个).
如果b<a<=2*b 只能到达(a%b,b)的状态。
代码:
//#include<CSpreadSheet.h> #include<iostream> #include<cmath> #include<cstdio> #include<sstream> #include<cstdlib> #include<string> #include<string.h> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #include<ctime> #include<bitset> #include<cmath> #define eps 1e-6 #define INF 0x3f3f3f3f #define PI acos(-1.0) #define ll __int64 #define LL long long #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #define M 1000000007 //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; int gcd(ll a,ll b) { if(a<b) //求出谁大 swap(a,b); if(b==0) //终止 必输状态 return 0; if(a>2*b) //必胜 return 1; return gcd(b,a%b)^1; //和拿了之后的输赢情况相反 } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); ll a,b; while(scanf("%I64d%I64d",&a,&b)) { if(!a&&!b) break; int ans=gcd(a,b); if(ans) printf("Stan wins\n"); else printf("Ollie wins\n"); } return 0; }