说在前面
刷博弈……
题目
题目大意
公平组合游戏
给出
堆石子,每堆石子初始都只有一个
可以合并两堆石子,得到一堆石子,石子个数等于原来两堆石子数之和
对于双方玩家,唯一允许的操作是:将两堆石子合并,且合并之后石子个数不能超过
询问是否先手必胜
范围:
数据组数:
输入输出格式
输入格式:
第一行一个整数
,表示数据组数
接下来
行,每行两个整数
,含义如题
输出格式:
对于每组数据,输出一行:
如果先手必胜输出
,不然输出
解法
(感觉比较神的一道题,看了lych的题解,这里只是整理思路)
首先可以确定,只有最终的合并次数,对答案有影响
偶数次先手必败,奇数次先手必胜
那么对于任意一个初始局面,先手都希望合并奇数次,而后手都希望合并偶数次
结论是,双方一定都可以达到合并次数最多的局面
合并次数最多的情况,显然就是石子堆都变成了这样:
证明:假设这样的合并次数是偶数,那么后手一定可以达到这个局面
- 首先如果 那么显然只能是这个局面
- 考虑现在石子个数是
(此时
为奇数,偶数情况类似),首先先手肯定会合并两个石子,称这一堆为「大堆」,然后后手会将一堆石子合并到「大堆」里。
接下来,如果先手合并了两个石子,后手就把这两个石子和最大的一堆合并。不然的话他们都会将石子向「大堆」合并。每次后手操作之后,大堆总是奇数个,所以到达 局面时,后手胜
同理,对于后手,可以推广到
局面,
局面
对于先手,也可以用类似的证明。比如对于
颗石子,先手始终将石子向大堆合并,最后一步要么是
,要么是
,然后可以得出先手必胜
然后也可以推广到
的局面
于是这题就做完了
下面是代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int T ;
long long N , M ;
int main(){
scanf( "%d" , &T ) ;
while( T -- ){
scanf( "%lld%lld" , &N , &M ) ;
long long t = ( N / M ) * ( M - 1 ) + ( N %M ? N %M - 1 : 0 ) ;
if( t&1 ) puts( "0" ) ;
else puts( "1" ) ;
}
}