题意:
有两堆石子,分别有a个和b个。
现在两个人玩游戏,有两种拿石子方法:
1.选择一堆石子,可以拿任意个;
2.选择两堆石子,可以同时拿掉相同个。
然后假设这俩人都很聪明,问这俩人谁胜。
如果胜,输出胜利的方案。
第一行是拿掉两堆石子相同个数,第二行是拿一堆石子不同个数。
解析:
列出sg函数的转移,会发现以下状态都是必败的:
1,2
3,5
4,7
6,10
8,13
9,15
11, 18
...
由此可以发现,必败态是由差值1,2,3,4...一直往后推出来的。
所以先把所有必败态找出来。
然后每次给俩数的时候,二分去找位置就行了。
他们的位置,减掉相同数的时候是他们之间的差值那组;
只找一堆的是小的数a在B中的位置那组。
看代码就懂了。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
using namespace std;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = 4 * atan(1.0);
const double ee = exp(1.0);
const int maxn = 1000000 + 10;
int losA[381971], losB[381971];
int num[maxn];
int main()
{
#ifdef LOCAL
freopen("in.txt", "r", stdin);
#endif // LOCAL
memset(losA, 0, sizeof(losA));
memset(losB, 0, sizeof(losB));
memset(num, 0, sizeof(num));
int cnt = 1;
for (int i = 1; i < maxn && i + cnt < maxn; i++)
{
if (num[i] == 0)
{
num[i] = 1;
num[i + cnt] = 1;
losA[cnt] = i;
losB[cnt] = i + cnt;
cnt++;
}
}
// cout << cnt << endl;
int a, b;
while (~scanf("%d%d", &a, &b))
{
if (!a && !b)
break;
int posA = lower_bound(losA, losA + cnt, a) - losA;
int posB = lower_bound(losB, losB + cnt, b) - losB;
if (losA[posA] == a && losB[posB] == b)
{
printf("0\n");
continue;
}
printf("1\n");
int pos = b - a;
printf("%d %d\n", losA[pos], losB[pos]);
if (num[a])
{
pos = lower_bound(losB, losB + cnt, a) - losB;
printf("%d %d\n", losA[pos], losB[pos]);
}
}
return 0;
}