传送门:HDU 1729
Problem Description
This game is a two-player game and is played as follows:
1.There are n boxes; each box has its size. The box can hold up to s stones if the size is s.
2. At the beginning of the game, there are some stones in these boxes.
3. The players take turns choosing a box and put a number of stones into the box. The number mustn’t be great than the square of the number of stones before the player adds the stones. For example, the player can add 1 to 9 stones if there are 3 stones in the box. Of course, the total number of stones mustn’t be great than the size of the box.
4. Who can’t add stones any more will loss the game.
Give an Initial state of the game. You are supposed to find whether the first player will win the game if both of the players make the best strategy.
Input
The input file contains several test cases.
Each test case begins with an integer N, 0 < N ≤ 50, the number of the boxes.
In the next N line there are two integer si, ci (0 ≤ ci ≤ si ≤ 1,000,000) on each line, as the size of the box is si and there are ci stones in the box.
N = 0 indicates the end of input and should not be processed.
Output
For each test case, output the number of the case on the first line, then output “Yes” (without quotes) on the next line if the first player can win the game, otherwise output “No”.
Sample Input
3
2 0
3 3
6 2
2
6 3
6 3
0
Sample Output
Case 1:
Yes
Case 2:
No
题意:
2个玩家,有N个箱子,每个箱子的大小是Si,游戏开始前,就有一些石子在这些箱子里了。
游戏者轮流选择箱子,然后把石子放入箱子里。并且放入的石子数量不能大于原来箱子里就有的石子的数量的平方。
比如说,一个箱子里已经有了3个石头,则可以放1-9个石头(小于箱子的容量)。
当轮到某人时,不能再放石子则为输。
问能否找到一种策略使先手必赢。
题解:
sg函数的dfs。
这里推荐有个讲sg函数讲的超好的博客:点这里
设每个箱子的容量为Si,已有的石子数量为Ci.
显然对于每个箱子,我们有sg(S,S)=0;(先手必输)
我们找最大的有个数p,使p*p+p<S;
当C>p时
我们肯定可以直接取到S,因为C*C+C>S恒成立。那么当取到S后就变成了sg(S,S)的状态,
因为sg(S,S)=0,所以这种情况先手必胜,sg(S,C)=S-C;
当C=p时
因为我们最多取C*C个,达不到S,那么下一个人一定可以在下一轮取到(S,S)的状态,
所以这种情况先手必输,即sg(S,C)=sg(S,P)=0;
当C<p时
我们不能确定这个状态,所以我们要判断先手可不可以到达(p,C)的状态,如果能到那么下一个状态就是(S,C==p),这个状态是先手必输的,即第二个人一定会输。如果不能取到,第二个人就一定可以到达这个状态,即第一个人一定会输。递归求解就行。
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int n;
ll s,c;//s是容积,c是盒子里的宝石数
ll sg[55];
bool vis[55];
int SG_dfs(int s,int c)
{
int t=sqrt(s);
while(t*t+t>=s)//找第一个满足t*t+t<s的t
{
t--;
}
if(c>t) return s-c;//先手必赢
else if(c==t) return 0;//先手必输
else return SG_dfs(t,c);//判断能否取到t,c状态
}
int main()
{
int ca=0;
while(scanf("%d",&n)&&n)
{
int ans=0;
memset(sg,-1,sizeof(sg));
for(int i=1;i<=n;i++)
{
scanf("%I64d%I64d",&s,&c);
ans^=SG_dfs(s,c);
}
if(ans==0) printf("Case %d:\nNo\n",++ca);
else printf("Case %d:\nYes\n",++ca);
}
return 0;
}