Problem Statement
Alice and Brown loves games. Today, they will play the following game.
In this game, there are two piles initially consisting of X and Y stones, respectively. Alice and Bob alternately perform the following operation, starting from Alice:
- Take 2i stones from one of the piles. Then, throw away i of them, and put the remaining i in the other pile. Here, the integer i (1≤i) can be freely chosen as long as there is a sufficient number of stones in the pile.
The player who becomes unable to perform the operation, loses the game.
Given X and Y, determine the winner of the game, assuming that both players play optimally.
Constraints
- 0≤X,Y≤1018
Input
Input is given from Standard Input in the following format:
X Y
Output
Print the winner: either Alice
or Brown
.
题意:给x y两堆石头,每个人可以从一堆中取2i个(如果有),然后扔掉i个,i个放到另一堆。
做不了操作的输。
相对于我用的方法,这题其实不难。但为了庆祝第一次在比赛中做出了博弈题,还是写下来。
简单的方法,打表找规律。
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 110;
bool dfs(int x, int y)
{
bool ret = false;
for (int i = 1; (i<<1) <= x; i++)
{
if (!dfs(x-i*2, y + i))//如果可以到达一个必败态,则当前为必胜态
{
ret = true;
break;
}
}
for (int i = 1; !ret && (i<<1) <= y; i++)
{
if (!dfs(x + i, y - i*2))//如果可以到达一个必败态,则当前为必胜态
{
ret = true;
break;
}
}
//如果上面循环没进去,或者进去后找不到必败态,则当前是必败态
return ret;
}
int main()
{
freopen("in.txt","r",stdin);
int n = 10, m = 10;
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= m; j++)
{
bool win = false;
printf("%2d %2d %4s ", i, j, dfs(i, j)?" ": "lose");
}
puts("");
}
return 0;
}
很暴力的打表代码,甚至都没有记录状态。
只是打出了lose的状态。
用n = 5,m= 5,打印内容
0 0 lose 0 1 lose 0 2 0 3 0 4 0 5
1 0 lose 1 1 lose 1 2 lose 1 3 1 4 1 5
2 0 2 1 lose 2 2 lose 2 3 lose 2 4 2 5
3 0 3 1 3 2 lose 3 3 lose 3 4 lose 3 5
4 0 4 1 4 2 4 3 lose 4 4 lose 4 5 lose
5 0 5 1 5 2 5 3 5 4 lose 5 5 lose
可以很明显感受到必败态有规律得分布。就是差值小于等于1.
按照Atcoder官方题解说,差值小于等于1的状态只能变成差值大于1,而差值大于1的状态,都可以一步变成小于等于1
没看出来就打表找规律了。
自测了一下,不记录状态真的好慢,15×15就卡得不出结果了。
改了个记录搜索状态的,秒出结果。
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
const int N = 110;
int vis[N][N];
bool dfs(int x, int y)
{
if (vis[x][y] != -1)
return vis[x][y];
if (vis[y][x] != -1)
return vis[y][x];
bool ret = false;
for (int i = 1; (i<<1) <= x; i++)
{
if (!dfs(x-i*2, y + i))//如果可以到达一个必败态,则当前为必胜态
{
ret = true;
break;
}
}
for (int i = 1; !ret && (i<<1) <= y; i++)
{
if (!dfs(x + i, y - i*2))//如果可以到达一个必败态,则当前为必胜态
{
ret = true;
break;
}
}
vis[x][y] = vis[y][x] = ret;
//如果上面循环没进去,或者进去后找不到必败态,则当前是必败态
return ret;
}
int main()
{
int n = 15, m = 15;
memset(vis, -1, sizeof(vis));
for (int i = 0; i <= n; i++)
{
for (int j = 0; j <= m; j++)
{
bool win = false;
printf("%2d %2d %4s ", i, j, dfs(i, j)?" ": "lose");
}
puts("");
}
return 0;
}