bzoj1188: [HNOI2007]分裂游戏

来源:互联网 发布:精灵恢复软件 注册码 编辑:程序博客网 时间:2024/06/04 22:06

传送门: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\n",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\n",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\n",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\n",i-1,j-1,k-1);if (!tot) puts("-1 -1 -1");printf("%d\n",tot);}return 0;}



0 0
原创粉丝点击