题目描述:
有 N 堆石子
每堆石子有 数量 A 和 参数 K
两位选手每次选一堆石子进行取出,可以取 1-floor(A/k)(A为当前本堆石子数量,并不是常量)
题目分析:
WTF!!!
第一次做一点都不裸的Nim 博弈
首先,打表程序蛮好写的
int dfs(int x,int k)
{
//printf("%d %d\n",x,k);
if(~SG[x][k]) return SG[x][k];
if(x==0) return 0;
if(x<k) return 0;
bool vis[10001];
memset(vis,0,sizeof(vis));
for(int i=1;i<=x/k;i++)
{
if(~SG[x-i][k]) vis[SG[x-i][k]]=1;
else vis[dfs(x-i,k)]=1;
}
for(int i=0;;i++)
if(!vis[i])
{
SG[x][k]=i;
//printf("x:%d k:%d SG[x][k]:%d x%%k:%d x/k:%d\n",x,k,i,x%k,x/k);
return i;
}
}
然而
1<=A,K<=109
1
<=
A
,
K
<=
10
9
所以又到了喜闻乐见的找规律时间了.
找规律?
以下找规律转化内容均来着SD神犇rqy orz
SG[k∗x][k]=x且SG[k∗x+b][k]=SG[(k−1)∗x+(b−1)][k]
S
G
[
k
∗
x
]
[
k
]
=
x
且
S
G
[
k
∗
x
+
b
]
[
k
]
=
S
G
[
(
k
−
1
)
∗
x
+
(
b
−
1
)
]
[
k
]
哇,这规律咋找的?
我们固定一个 K 然后输出一下 SG[1-n][K]
会发现如果我们搞出的SG排列,把K的倍数删去,一点变化都没有
比如k=2的时候数列是0 0 1 0 2 1 3 0 4 2 5 1 6 3…
偶数位显然是0 1 2 3 4 5 6…
把所有奇数位拿出来之后还是0 0 1 0 2 1 3 0 4 2 5 1 6 3
不得不说 rqy就是强
直接这么算会T
可以发现从kx+b到(k-1)x+(b-1)减去了(x+1)
不停地减去x+1直到k变小为止
一共要减ceil(b/(x+1))次,也就是(b+x)/(x+1)(下取整)次
题目链接:
Ac 代码:
#include <cstdio>
#include <iostream>
int SG(int a,int k)
{
int x=a/k,b=a%k;
if(!b) return x;
int t=(b+x)/(x+1);
return SG(a-t*(x+1),k);
}
int main()
{
int n;
scanf("%d",&n);
int ans=0;
for(int i=1;i<=n;i++)
{
int a,k;
scanf("%d%d",&a,&k);
ans^=SG(a,k);
}
puts(ans?"Takahashi":"Aoki");
return 0;
}