[QSCOJ39]喵哈哈村的代码传说 第五章 找规律
题目大意:
给你n堆排,两人轮流对其中一堆牌进行以下操作之一:
1.从这堆牌中取出任意数量的牌;
2.将这这堆牌分为任意大小的3堆牌。
不能操作者负。
问先手是否有必胜策略。
思路:
尝试构造sg函数,游戏的状态为某堆牌中牌的数量,
打表计算发现当x为8的倍数时,sg(x)=x-1;
当x在模8意义下为7时,sg(x)=x+1;
否则sg(x)=x。
手算了以下x=0~8时的情况,解释如下:
当x=0时,先手没法操作,sg(x)=0;
当x=1时,当前的后继状态为(0),sg(x)=mex{sg(0)}=1;
当x=2时,当前的后继状态为(0)(1),sg(x)=mex{sg(0),sg(1)}=2;
当x=3时,当前的后继状态为(0)(1)(2)(1 1 1),sg(x)=mex{sg(0),sg(1),sg(2),...,sg(1)^sg(1)^sg(1)}=3;
……
当x=7时,当前的后继状态为(0)~(6)(1 1 5)(1 2 4)(1 3 5)(2 2 3),此时(1 2 4)所对应的sg值为sg(1)^sg(2)^sg(4),sg(7)=8;
而当x=8时,当前的后继状态中(7)的sg值为8,而其它的后继状态中sg值也没有等于7的,所以sg(x)=7。
程序实现十分简单。
1 #include<cstdio> 2 #include<cctype> 3 inline int getint() { 4 register char ch; 5 while(!isdigit(ch=getchar())); 6 register int x=ch^'0'; 7 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 8 return x; 9 } 10 inline int getsg(const int &x) { 11 if(x%8==0) return x-1; 12 if(x%8==7) return x+1; 13 return x; 14 } 15 int main() { 16 for(register int T=getint();T;T--) { 17 int ans=0; 18 for(register int n=getint();n;n--) { 19 ans^=getsg(getint()); 20 } 21 puts(ans?"First player wins.":"Second player wins."); 22 } 23 return 0; 24 }