N
N
N堆石子,每堆有
A
i
A_i
Ai颗,两个人轮流取,每次选择其中一堆,当其剩下石子数为
x
x
x时,取的石子数不能超过
x
/
k
x/k
x/k下取整,每堆的
k
k
k是一个定值,不能取的人为负。
N
≤
200
N≤200
N≤200
A
i
,
k
i
≤
1
0
9
A_i,k_i≤10^9
Ai,ki≤109
题解
显然可以先计算出对于不同
k
k
k的每个状态的SG函数值,从
0
0
0开始打个表出来,
把这些数
k
k
k个一行,会发现第一列从
0
0
0开始依次递增
1
1
1,第一行全为
0
0
0,当把第一列的数全部删去后,剩下的数也满足这个规律,
那么一开始先把
A
i
A_i
Ai加一,再这样一直删下去就可以求出当前
A
i
A_i
Ai的函数值。
一开始以为这样就可以过了,其实发现是会TLE的,
有可能
A
i
A_i
Ai特别大,但
A
i
/
k
i
A_i/k_i
Ai/ki也特别大,以至于每次只能删去很少的几个数,需要重复操作很多遍,
那么直接考虑一次性多删一些。
每次相当于给
A
i
A_i
Ai减去
(
A
i
−
1
)
/
k
(A_i-1)/k
(Ai−1)/k下取整,当
(
A
i
−
1
)
/
k
(A_i-1)/k
(Ai−1)/k下取整的值没变时,每次减去的数值就是一样的,那么直接就算最多可以先重复删多少个这个值即可。
代码
#include<cstdio>usingnamespace std;intsolve(int x,int k){if(x <= k)return0;if((x -1)% k ==0)return(x -1)/ k;int d =(x -1)/ k * k +1, t =(x -1)/ k +1;returnsolve(x -((x -1- d)/ t +1)* t, k);}intmain(){int n, s =0, x, k;scanf("%d",&n);while(n--){scanf("%d%d",&x,&k);
s ^=solve(x +1, k);}if(s)printf("Takahashi");elseprintf("Aoki");return0;}