HDU 1525

题目大意:有2个数,2个人轮流把大的数(设为a)减去小的数(设为b)的倍数(不能超过大的数),一直到有一方能把某个数减到0,该方获胜。Stans先走,问最后赢的是谁。

题目分析:

每次减去b的倍数,那么直到不能减b(再减去1个b都会变成负数)时,就进行下2个数的“新”一轮减法了。什么时候这两个数(a,b)不能减(原本b不作为减数)?当a'小于b的时候,其实也就是当a减去(a/b)的时候,这时候a' = a%b。

当局面变成(a',b)时,事实上,大数变成了b,小数变成了a'。是不是觉得很熟悉?对的,这不就是GCD么?

然后每次从大的数(a)中减去x个小的数(b),其实很类似于每次从一共有(a/b)个石子的堆中取x个。—— 当a/b==0时,这堆石子取完;因为a/b == 0时,按照规则,开始进行(b,a%b)了。

但是这和nim还是有区别的,因为这些石子堆是有顺序的,必须先取完第一堆,再取下一堆。

注意的是:我们要从终态(就是下完这一步就整个博弈结束了)往上推。

 

 1 #include<stdio.h>
 2 #include<iostream>
 3 #include<string.h>
 4 
 5 using namespace std;
 6 int s[1111],cnt;
 7 void gcd(int a,int b){
 8   s[cnt++] = a/b;
 9   if(a%b == 0)return ;
10   gcd(b,a%b);
11 }
12 
13 int main()
14 {
15 #ifdef LOCALL
16 //    freopen("in.txt","r",stdin);
17   //freopen("out2.txt","w",stdout);
18 #endif
19   int n,m;
20   while(cin>>n>>m,n!=0||m!=0){
21     int max = n+m;n = n>m?n:m;m = max - n;
22     if(n%m==0){cout<<"Stan wins
";continue;}
23     cnt = 0;
24     gcd(n,m);
25     int ans = 0;
26     for(int i = cnt-1;i>=0;i--){
27       if(ans == 0||(ans == 1&&s[i]>1) ) //如果下一步是sg = 0,P,或者下一步原本是sg != 0,N,但能通过取s[i]剩0或者1来控制下一步sg值为0,此次我方能赢
28         ans = 1;
29       else ans = 0;//ans == 1&&s[i]==1的情况不能控制,也就是现在是P:0,我方必败
30     }
31     //cout<<ans<<endl;
32     if(ans)cout<<"Stan wins
";
33     else cout<<"Ollie wins
";
34   }
35     return 0;
36 }

 

原文地址:https://www.cnblogs.com/PeanutPrince/p/3523833.html