分析
对于 \(nim\) 游戏的话,可以去看P2197进行博弈论相关知识的学习。
在得到结论之后,我们就是要求,所有车辆石头的异或和,是否为零,是则后手赢,反之先手赢。
我们考虑每一位来单独处理,计算这些车石头数在每一位有多少个 \(1\),对于第 \(i\) 位而言,若以函数的角度理解,它的周期是 \(2^{i+1}\),每一周期里,有 \(2^i\) 个数字该位为 \(1\)。
因此对于每一位,我们就可以先找出 \(x\) 当前所处的连续 \(1\) 或连续 \(0\) 的片段最远延伸到了多少,然后再找出多少个满周期,最后再加上剩余的数里有多少个该位为 \(1\)。
具体的实现可以详见代码。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int cnt[60];
int cf[60];
int mx=57;
int n,x,mm;
signed main()
{
cf[0]=1;
for(int i=1;i<=mx;i++)cf[i]=cf[i-1]*2;
cin>>n;
for(int i=1;i<=n;i++){
cin>>x>>mm;
for(int j=0;j<=mx;j++){
int m=mm;//这个东西导致我错了很久
int sum=x/cf[j]+1;//找出当前连续段的末端位置
//每一连续段大小都是2^j,所以直接除后加一,乘上2^j减1就是所求
if(x&cf[j]){//x是从1开始,后面取完周期就是从0开始
sum=sum*cf[j]-1;
if(sum-x+1>m)cnt[j]+=m;//特判
else {
cnt[j]+=sum-x+1;
m-=sum-x+1;
sum=m/(cf[j]*2);//周期数
m-=cf[j]*2*sum;
cnt[j]+=sum*cf[j];//一半0,一半1
m-=cf[j];//先有2^j个0
if(m>0)cnt[j]+=m;
}
}
else {
sum=sum*cf[j]-1;
if((sum-x+1)>m)cnt[j]+=0;
else {
m-=sum-x+1;
sum=m/(cf[j]*2);
m-=cf[j]*2*sum;
cnt[j]+=sum*cf[j];//前面同理
if(m>0)cnt[j]+=min(m,cf[j]);//前面就是1了
}
}
cnt[j]%=2;//因为是异或,直接模2即可
}
}
for(int i=0;i<=mx;i++){
if(cnt[i]){//异或和不为0,先手必胜
puts("tolik");
return 0;
}
}
puts("bolik");
return 0;
}