一、威佐夫博弈:
有两堆各若干个物品,两个人轮流从任一堆取至少一个或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。

若两堆物品的初始值为(x,y),且x<y。
令z=y-x;w=(int)((sqrt(5)+1)/2 * z)
若w==x则先手必败,否则先手必胜。

二、一些性质:
1。
第k个必败状态时((sqrt(5)+1)/2 * k , (sqrt(5)+1)/2 * k+k)

2。
先手必败的局势
第一个(0,0)

第二个(1,2)

第三个(3,5)

第四个(4 ,7)

第五个(6,10)

第六个 (8,13)

第七个 ( 9 , 15)

第八个 ( 11 ,18)

第n个(a[k],b[k])
我们称先手必败局势为奇异局势。
可以看出,a[0]=b[0]=0,a[k]是未在前面出现过的最小自然数,而 b[k]= a[k] + k。

则:
1。任何自然数都包含在一个且仅有一个奇异局势中。
2。任意操作都可将奇异局势变为非奇异局势。
3。采用适当的方法,可以将非奇异局势变为奇异局势。

3。
(1)、一个状态是必败态,当且仅当它的所有后继状态都是必胜态;而一个状态是必胜态,只要它的后继状态有一个以上的必败态即可。
(2)、(a,b) 和 (b, a) 的胜负性是相同的。
(3)、若 (a, b) 是必败态,则对于所有的 x > a 和 y > b,(x, b) 和 (a, y) 是必胜态。
(4)、若 (a, b) 是必败态,则对于所有的 d > 0,(a + d, b + d) 是必胜态。
(5)、在所有的必败态中,每个数字恰巧出现一次。
(6)、矩阵中每行第一个数恰巧是前面每一行中没有出现过的最小正整数。
(7)、矩阵第 i 行的第二个数正好为第一个数加上 i

例题:P2252 [SHOI2002]取石子游戏|【模板】威佐夫博弈

题目背景

题目描述
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。

输入格式
输入共一行。

第一行共两个数a, b,表示石子的初始情况。

输出格式
输出共一行。

第一行为一个数字1、0或-1,如果最后你是胜利者则为1;若失败则为0;若结果无法确定则为-1。

输入输出样例
输入 #1 复制
8 4
输出 #1 复制
1
说明/提示
[数据范围]

50%的数据,a, b <= 1000

100%的数据,a, b <= 1 000 000 000

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<queue>
#define ll long long
#define pr make_pair
#define pb push_back
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e15;
const int mod=1e9+7;
const double eps=1e-8;
const int maxn=5000100;
int main(void)
{
    ll x,y;
    scanf("%lld%lld",&x,&y);
    if(x>y) swap(x,y);
    ll z=y-x;
    if(x==(ll)((sqrt(5)+1)/2*z)) printf("0\n");
    else printf("1\n");
    return 0;
}