传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1188
思路:这题比较特殊,每个豆子是一个独立的游戏,SG的下标是豆子所处的位置。
知道了这一点就很好做了。
首先对于一个位置的两个豆子,一个人走一步,另一个人也可以走这一步,所以就抵消了
从SG函数的角度理解,这两个豆子的SG值相同,最后反正会被异或掉。
所以豆子数等于a[i]%2
对于输出方案,枚举i,j,k,表示第一步由i移向j和k。
怎么判断是否合法?只要判断移动后是否为先手必败,就是移动后的局面SG值为零。
移动后的SG值只要通过原来的SG^SG[i]^SG[j]^SG[k]得到。
这一步也很好理解,i处豆子少了一个,j,k豆子多了一个,都只要异或一下就可以了。
#include<cstdio> #include<cstring> #include<algorithm> const int maxn=27; using namespace std; int T,n,a[maxn],sg[maxn],tot,ans;bool bo[20010]; int getsg(int x){ if (sg[x]!=-1) return sg[x];//printf("xxxxx%d ",x); memset(bo,0,sizeof(bo)); for (int i=1;i<x;i++) for (int j=1;j<=i;j++) bo[getsg(i)^getsg(j)]=1;//,printf("%d %d ",i,j) for (int i=0;;i++) if (!bo[i]) return sg[x]=i; } int main(){ memset(sg,-1,sizeof(sg)); sg[1]=0;for (int i=2;i<26;i++) sg[i]=getsg(i); //for (int i=1;i<=20;i++) printf("%d ",sg[i]); scanf("%d",&T); while (T--){ scanf("%d",&n),ans=tot=0; for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=n;i++) if (a[i]&1) ans^=sg[n-i+1]; for (int i=1;i<=n;i++) for (int j=i+1;j<=n;j++) for (int k=j;k<=n;k++) if (!(ans^sg[n-i+1]^sg[n-j+1]^sg[n-k+1])) if (++tot==1) printf("%d %d %d ",i-1,j-1,k-1); if (!tot) puts("-1 -1 -1"); printf("%d ",tot); } return 0; }