POJ 1067 取石子游戏(威佐夫博弈)

题目链接:http://poj.org/problem?id=1067


题面:

取石子游戏
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 36951   Accepted: 12512

Description

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

Input

输入包含若干行,表示若干种石子的初始情况,其中每一行包含两个非负整数a和b,表示两堆石子的数目,a和b都不大于1,000,000,000。

Output

输出对应也有若干行,每行包含一个数字1或0,如果最后你是胜者,则为1,反之,则为0。

Sample Input

2 1
8 4
4 7

Sample Output

0
1
0

Source

NOI


解题:

    慢慢推了几组之后,就会发现(1,2),(3,5),(4,7)......这些数对是必败态。推到这里想必大家都知道如何往下推了,(ai,bi),ai是之前没有出现过的最小自然数,而ci是之前没有出现过的最小自然数间隔,bi=ai+ci。为什么呢?因为(ai,bi-x),(bi>x>0)这些间隔在之前都已经出现过,只需要将两数共同减去相同一个数,便可到达必败态,故为必胜态。而(ai-x,bi),因为ai-x在前面都已经出现过,只需要将bi调整到前面(ai-x,bi-y)对应的必败态即可,故也为必胜态。只有(ai,bi),无法退回到之前的任一必败态,故为必败态。

    序列为(1,2),(3,5),(4,7),(6,10),(8,13),(9,15),(11,18),(12,20),(14,23)......

    推了这么多,然而并无卵用。

    因为这是普通人都不可能一眼发现的快哭了

    这是威佐夫的毕生研究,结论如下:

    ai为[p*i],bi为[(p+1)*i],其中p为((sqrt(5.0)+1)/2)。[]为向下取整。

    有了以上结论,那么此题就可以解了。(d=bi-ai),用此时的d带入ai的计算公式,算出ai',看ai'是否等于给出的ai,是则说明为必败态,不是则说明不是必败态。

    详细证明:http://www.cppblog.com/coreBugZJ/archive/2012/06/04/177481.html

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <set>
using namespace std;

int main()
{
    int a,b,dif,tmp;
	while(cin>>a>>b)
	{
		if(a>b)
			swap(a,b);
		dif=b-a;
		tmp=dif*(1.0+sqrt(5.0))/2;
		if(a==tmp)
			cout<<"0\n";
		else cout<<"1\n";
	}
	return 0;
}


你可能感兴趣的:(HDU,博弈)