P1290 欧几里德的游戏
肯定是博弈论啦
因为大家都"完美地操作"
所以结果是肯定的
那考虑怎样先手才能控制必胜局面
设大的数是 a,另一个数是b
如果把数变成 b,a%b的局面必胜
那先手肯定走这一步,先手必胜
如果b,a%b的局面必输
那先手就要尽量避免,而且要尽量让后手变成 不得不取成b,a%b的必输局面
考虑怎样才有 不得不 取成b,a%b的必输局面
显然如果 a < 2 * b
就只能 变成 b,a-b,即 b,a%b
如果先手时的 a >=2 * b
那么先手只要把 a 减到 a%b+b 就能保证必胜(显然只要减若干个 b ,a 就可以变成 a%b+b)
如果先手面对的是 a< 2 * b的局面...
那就只能减了...
那此时就成了 b , a%b的局面,而且是后手的回合了..
相当于现在后手成了先手,面对 b,a%b 的局面
然后继续判断下去就好了
复杂度log(a)...
讲一下复杂度的证明吧,不想听也可以跳过...
如果 a >= 2*b,那就结束了
否则 a < 2*b 所以 a/2 < b
那减完一次,显然只能减一个b,不然就变成了负数了
因为 a/2 < b,a/2 = a - a/2
所以 a - b < a - a/2 = a/2
即 每次减后 a 至少除以 2
所以最多只要log( a ) 次就能得出结果....
注意一下刚开始 a=b 的情况特判一下
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; long long n,m; int num; int main() { int t; cin>>t; while(t--) { num=0; cin>>n>>m; if(n<m) swap(n,m); if(n==m) { cout<<"Stan wins"<<endl; continue; } while(n<2*m)//如果n>=2*m,那么结果就确定了 { num++; n-=m; swap(n,m); } if(!(num&1)) cout<<"Stan wins"<<endl; //如果num为偶数,即当为 Stan 的回合时能保证比胜 else cout<<"Ollie wins"<<endl; //否则就是 Ollie 必胜 } return 0; }