题目大意:
就是Wythoff Game的原型, 每次可以拿其中一堆的任意数量或者两堆同时拿一样的任意数量, 拿走最后一颗石子的人胜
大致思路:
首先可以参考这篇Wythoff Game的论文:
Wythoff Game
其中提到了一个Beatty Theorem(贝蒂定理):
如果 a 和 b 都是无理数, 且 1a+1b=1 , 那么 {⌊a⌋,⌊2a⌋,⌊3a⌋...} 和 {⌊b⌋,⌊2b⌋,⌊3b⌋...} 两个集合之间没有相同元素且他们并组成正整数集 ( ⌊a⌋ 表示向下取整)
另外Wythoff Game当中一个重要的表:
The Sequence of Safe Pairs (A, B)
n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | … |
---|---|---|---|---|---|---|---|---|---|---|---|---|
A | 0 | 1 | 3 | 4 | 6 | 8 | 9 | 11 | 12 | 14 | 16 | … |
B | 0 | 2 | 5 | 7 | 10 | 13 | 15 | 18 | 20 | 23 | 26 | … |
这里我们是不妨假设了 A≤B
其中 (A,B) 是 P 点的条件是 A=⌊ϕn⌋,B=A+n 是 第n个 P 点, 当然 B也可以写作⌊ϕ2n⌋
其中 ϕ 是黄金比例 ϕ=1+5√2
上表中的一些性质
将第 i 列的 A 和 B 记做 A[i],B[i] 的话, B[i]=A[i]+i , 并且, 如果第 i 列是 (A[i],B[i]) , 那么第 B[i] 列一定满足 A[B[i]]=A[i]+B[i]
对于每一个 A[k] , A[k] 一定是前面 (A[i],B[i]) 中没有出现过的最小自然数, 并且任何一个自然数都包含在一个且仅有的一个 P 点中(也有文章称为奇异局势), 这里我们只考虑了 A[i]≤B[i] 的局势
那么接下来说明任意操作都可以将奇异局势( P 点)变成非奇异局势( N 点)
如果 (A[k],B[k]) 是奇异局势( P 点), 如果只改变其中一个数, 那么得到的分量不可能在其他奇异局势中( P 点), 因为每个奇异局势中的自然数是唯一的, 如果将两个数同时减少, 由于两个数的差不变, 不可能是其他奇异局势的差, 因为第i个奇异局势的差是 B[i]−A[i]=i , 于是从奇异局势( P 点)只能变成非奇异局势( N 点)
对于一个非奇异局势( N 点),记为 (a,b) , 如果 b=a 可以变为 (0,0) 的奇异局势, 那么 a<b 时 如果 a=A[k],b>B[k] , 那么可以变为奇异局势 (A[k],B[k])
如果 a=A[k],b<B[k] , 那么两堆同时拿走 A[k]−A[b−A[k]] , 很明显由于 B[k]>b>a>A[k] , 这里取走 A[k]−A[b−A[k]] 中 b−A[k]<B[k]−A[k]=k , 所以肯定是可取的, 那么这样就变成了 (A[b−A[k]],b−A[k]+A[b−A[k]]) , 也就是 (A[b−A[k]],A[b−A[k]]+(b−A[k])) , B[b−A[k]]=A[b−A[k]]+(b−A[k]) 所以变成了奇异局势( P 点)
如果 a>A[k],b=B[k]=A[k]+k , 那么从第一队中拿走多余的即可变为 (A[k],B[k)
如果 a<A[k],b=A[k]+k=B[k]
那么当 a=A[j] 时 (j<k) 从第二堆拿走 b−B[j] 即可
当 a=B[j] 时 (j<k) , 从第二堆拿走 b−A[j] 即可
以上两种一定包含了所有情况, 因为之前找到的性质: A[i] 是前面没有出现的最小自然数
以上是学习到的所有Wythoff Game相关的东西了, 这里了一下:
接下来就是代码了, 利用黄金分割来判断是否是(A[i], B[i])即可
代码如下:
Result : Accepted Memory : 1576 KB Time : 31 ms
/* * Author: Gatevin * Created Time: 2015/5/8 10:14:35 * File Name: Rin_Tohsaka.cpp */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e)
#define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl
const double gold_ratio1 = (1 + sqrt(5.)) / 2;
const double gold_ratio2 = (sqrt(5.) - 1) / 2;
int a, b;
int main()
{
while(scanf("%d %d", &a, &b) != EOF)
{
if(a > b) swap(a, b);
int t = floor(a*gold_ratio2);
if(floor(t*gold_ratio1) != a)
{
if(a + t + 1 == b) puts("0");
else puts("1");
}
else
{
if(a + t == b) puts("0");
else puts("1");
}
}
return 0;
}