[Jzoj] 3033.石子游戏

题目大意

两人取一堆 n n n个石子 先手不能全部取完 之后每人取的个数不能超过另一个人上轮取的数 ∗ K *K K。取完最后一个石子的人获胜。给 n , K n,K nK判断先手必胜并求第一步。

题目解析

博弈论
当k=1的时候 可知必败局面都是2^i 将n分解成二进制,然后先手取掉最后一个1.然后对方必然无法去掉更高的1,而对方取完我方至少还能拿掉最后一个1 导致对方永远取不完。当k=2的时候,必败局面都是斐波那契数列。利用“先手去掉最后一个1,则后手必不能去掉更高阶的1导致取不完”的思想,斐波那契数列有一个非常好的性质就是:任意一个整数可以写成斐波那契数列中的不相邻的项的和,于是将n写成这种形式,先取走最后一个1,对方能取的数是这个数*2,小于高2位的1,所以取不完。当K>2的时候, 想办法构造数列,将n写成数列中一些项的和,使得这些被取到的项的相邻两个倍数差距>k 那么每次去掉最后一个1 还是符合上面的条件。 设这个数列已经被构造了i 项,第 i 项为a[ i ],前 i 项可以完美对1…b[ i ] 编码使得每个编码的任意两项倍数>K 那么有a[ i+1 ] = b[ i ] + 1;这是显然的因为b[ i ] + 1没法构造出来,只能新建一项表示然后计算b[ i+1] 既然要使用 a[ i+1 ] 那么下一项最多只能是某个 a[ t ] 使得 a[ t ] * K < a[ i+1 ] 于是b[ i ] = b[ t ] + a[ i+1 ]然后判断n是否在这个数列里面如果在,那么先手必败。否则不停的减掉数列a中的项构造出n的分解,最后一位就是了。

代码

#include
using namespace std;
int n,k,T,ss;
int a[2000005],b[2000005];
int main()
{
	cin>>T;
	a[0]=b[0]=1;
	while(T--)
	{
	  cin>>n>>k;
	  ss++;
	  cout<<"Case "<=a[i])
	  	  {
	  	  	ans=a[i];
	  	  	n-=a[i];
		  }
		  i--;
		}
		cout<

你可能感兴趣的:([Jzoj] 3033.石子游戏)