思路:
这就是K倍动态减法游戏,可以参考曹钦翔从“k倍动态减法游戏”出发探究一类组合游戏问题的论文。
首先k=1的时候,必败态是2^i,因为我们把数二进制分解后,拿掉最后一个1,那么会导致对方永远也取不完,我们可以拿到最后一个1.
k=2的时候,必败态是斐波那契数列,因为任何一个整数n都可以写成两项斐波那契数的和,所以我们拿掉1,对方永远取不完高两位的数。
k的时候我们必须构造数列,将n写成数列中一些项的和,使得这些被取到的项的相邻两个倍数差距>k 那么每次去掉最后一个1 还是符合上面的条件。设这个数列已经被构造了i 项,第 i 项为a[ i ],前 i 项可以完美对1..b[ i ] 编码使得每个编码的任意两项倍数>K 那么有
View Code
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的分解,最后一位就是了。
代码如下:
1 #include<cstdio> 2 int a[1000000],b[1000000]; 3 int main() 4 { 5 int i,j,t,n,k,c=0,ans; 6 scanf("%d",&t); 7 while(t--){ 8 scanf("%d%d",&n,&k); 9 i=j=0; 10 a[0]=b[0]=1; 11 while(a[i]<n){ 12 i++; 13 a[i]=b[i-1]+1; 14 while(a[j+1]*k<a[i]) j++; 15 if(a[j]*k<a[i]) b[i]=b[j]+a[i]; 16 else b[i]=a[i]; 17 } 18 printf("Case %d: ",++c); 19 if(a[i]==n) puts("lose"); 20 else{ 21 while(n){ 22 if(n>=a[i]){ 23 n-=a[i]; 24 ans=a[i]; 25 } 26 i--; 27 } 28 printf("%d ",ans); 29 } 30 } 31 return 0; 32 }