题目大意:
有
n
n
堆石子,每堆石子有个,有一个数
ki
k
i
现在两个人博弈,每
个人每次至多可以拿走数量的为
⌊xki⌋
⌊
x
k
i
⌋
石子,
x
x
为当前这一堆石子的
数量,谁不能拿就输了,求谁赢。
思路:
这一看就是SG函数的题目,然后就不会做了。。。
我们固定了的值为
3
3
后打表:
0 0 1 0 1 2 0 1 3 2
然后发现在时候,SG就等于
x/k
x
/
k
,这个时候SG函数的值是由前面
x/k
x
/
k
个数决定的,根据SG函数的定义,不难发现,前面的
x/k
x
/
k
个数就是
0
0
到,但是顺序肯定是打乱的。
如何求
x%k!=0
x
%
k
!
=
0
时的函数值呢?发现当整除k相等的时候,都是由这个点往前
⌊xk⌋
⌊
x
k
⌋
个数的SG函数的值决定的,由于整除的时候的值我们是知道的,往后推一个就相当于
x−⌊xk⌋−1
x
−
⌊
x
k
⌋
−
1
的值到了后面(这相当于是一个循环)。
然后我们就可以递归求函数了。但是会T。
每次往前递归是将坐标减去了
⌊xk⌋+1
⌊
x
k
⌋
+
1
,当k很大的时候会递归很多次,但是发现当k很大时候很长的一段区间减去的值都是相同的。所以我们直接一次性减去很多个相同的就可以了。
代码好短。。。
/*======================
* Author : ylsoi
* Problem : ARC91F
* Algorithm : SG
* Time : 2018.6.2
* ====================*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstring>
#include<climits>
using namespace std;
void File(){
freopen("ARC91F.in","r",stdin);
freopen("ARC91F.out","w",stdout);
}
template<typename T>bool chkmax(T &_,T __){return _<__ ? (_=__,1) : 0;}
template<typename T>bool chkmin(T &_,T __){return _>__ ? (_=__,1) : 0;}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define inf INT_MAX
const int maxn=1000+10;
int n,a,k,ans;
int get_SG(int x){
//cout<<x<<endl;
if(x%k==0)return x/k;
if((x-(x/k)-1)/k!=x/k)return get_SG(x-(x/k)-1);
int b=x-x/k*k,t=b/((x/k)+1);
return get_SG(x-t*((x/k)+1));
}
int main(){
File();
cin>>n;
REP(i,1,n){
cin>>a>>k;
ans^=get_SG(a);
}
if(ans)puts("Takahashi");
else puts("Aoki");
return 0;
}