[HNOI2007]分裂游戏
这个题太妙啦
我们发现如果把一堆石子看成一个独立游戏的话显然是不可以的,因为这样的话游戏根本就不独立,于是就自闭了
我们发觉这个东西本质上还是一个\(multi\)博弈,只不过这里的单个游戏变成了每一个石子,石子在不停的分裂
我们设\(sg_x\)表示一个石子在第\(x\)堆的\(SG\)函数
如果\(x=n\),那么这个石子显然不能再移动了,于是\(sg_x=0\)
如果\(x!=n\),我们就考虑这个石子分裂产生的新位置,于是\(sg_x=mex_{i<j<=k}\{sg_{j}\bigoplus sg_k\}\)
于是我们现在在\(O(n^3)\)的时间内就可以求出\(sg\)函数的值了
之后我们再\(O(n^3)\)枚举出示状态就可以了
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int sg[55],n,T,tax[100005],m;
int main() {
T=read();m=1;
while(T--) {
n=read();sg[n]=0;memset(sg,0,sizeof(sg));
for(re int i=n-1;i;--i,++m) {
for(re int j=i+1;j<=n;j++)
for(re int k=j;k<=n;k++)
tax[sg[j]^sg[k]]=m;
while(tax[sg[i]]==m) sg[i]++;
}
int ans=0,tot=0;
for(re int x,i=1;i<=n;i++)
x=read()&1,ans^=(x*sg[i]);
if(!ans) {puts("-1 -1 -1");puts("0");continue;}
for(re int i=1;i<=n;i++)
for(re int j=i+1;j<=n;j++)
for(re int k=j;k<=n;k++) {
ans^=sg[i];ans^=sg[j];ans^=sg[k];
if(!ans) {
if(!tot) printf("%d %d %d\n",i-1,j-1,k-1);
tot++;
}
ans^=sg[i];ans^=sg[j];ans^=sg[k];
}
printf("%d\n",tot);
}
return 0;
}