Industrial Nim
题面翻译
第一行给出 N N N 表示有 N N N 个采石场,接下来 N N N 行每一行一个 X i X_i Xi 一个 M i M_i Mi,表示第 i i i 个采石场有 M i M_i Mi 辆车,这个采石场中第 1 1 1 辆车的石头数量是 X i X_i Xi,第 2 2 2 辆车中有 X i + 1 X_i+1 Xi+1 个石头…第 M i M_i Mi 辆车的石头的数量是 X i + M i − 1 X_i+M_i-1 Xi+Mi−1。
有两个人每次从任意一辆车中取任意数量的石头(不能为 0 0 0 ),最后一个取完所有石头的赢。若先手赢输出"tolik",后手赢输出"bolik"。
1 ≤ n ≤ 1 0 5 1\le n\le 10^5 1≤n≤105
1 ≤ x i , m i ≤ 1 0 16 1\le x_i,m_i\le 10^{16} 1≤xi,mi≤1016
题目描述
There are $ n $ stone quarries in Petrograd.
Each quarry owns $ m_{i} $ dumpers ( $ 1<=i<=n $ ). It is known that the first dumper of the $ i $ -th quarry has $ x_{i} $ stones in it, the second dumper has $ x_{i}+1 $ stones in it, the third has $ x_{i}+2 $ , and the $ m_{i} $ -th dumper (the last for the $ i $ -th quarry) has $ x_{i}+m_{i}-1 $ stones in it.
Two oligarchs play a well-known game Nim. Players take turns removing stones from dumpers. On each turn, a player can select any dumper and remove any non-zero amount of stones from it. The player who cannot take a stone loses.
Your task is to find out which oligarch will win, provided that both of them play optimally. The oligarchs asked you not to reveal their names. So, let’s call the one who takes the first stone «tolik» and the other one «bolik».
输入格式
The first line of the input contains one integer number $ n $ ( $ 1<=n<=10^{5} $ ) — the amount of quarries. Then there follow $ n $ lines, each of them contains two space-separated integers $ x_{i} $ and $ m_{i} $ ( $ 1<=x_{i},m_{i}<=10^{16} $ ) — the amount of stones in the first dumper of the $ i $ -th quarry and the number of dumpers at the $ i $ -th quarry.
输出格式
Output «tolik» if the oligarch who takes a stone first wins, and «bolik» otherwise.
样例 #1
样例输入 #1
2
2 1
3 2
样例输出 #1
tolik
样例 #2
样例输入 #2
4
1 1
1 1
1 1
1 1
样例输出 #2
bolik
思路
我们该开始看题我们可以知道,这道题其实就是每个采石场都是个简单的Nim游戏(也就是如果先手必胜的话,异或和不为0,反之为0)。但我们如果直接去求异或和的话,会卡#13,因此我们得关注它的性质。
因为由题可知,每个采石场的石子是以公差为1的等差数列构成的,而且我们很显然知道奇数和偶数的异或和为1,然后我们知道特判一下len的长度(也就是结尾),然后再特判一下开头,然后直接对中间的数异或1即可。因此,我们就可以利用这一性质来写这道题了。
代码
//容易发现每个采石场都是个简单的Nim游戏
#include<iostream>
using namespace std;
int n;
int main(){
cin>>n;
int ans=0;
//这个超时了#13
// for(int i=1;i<=n;i++){
// int a,len;
// cin>>a>>len;
// while(len--)
// ans^=a++;
// }
//优化: 一个偶数和它的下一个奇数的异或和为1。正确性还是很显然的。
for(int i=1;i<=n;i++){
long long a,len;
cin>>a>>len;
if(a&1)ans^=a++,len--;//头
if(len&&len&1)ans^=a+len-1,len--;//尾巴
if(len&&(len/2)&1)ans^=1;//中间
}
if(ans)puts("tolik");
else puts("bolik");
return 0;
}