[BZOJ1188][HNOI2007]分裂游戏(博弈SG函数)
2016-12-22 23:29
453 查看
题目描述
传送门题解
本来想写一个二维的SG,一维是位置一维是个数,但是发现做不了多少就炸了。后来发现只有石子个数是奇数是有意义的,因为偶数的都可以模仿操作对吧。
那么这样的话就相当于是一坨1来做,然后每一次可以将一个游戏拆成两个游戏,这不就是典型的Multi-SG吗。
用SG函数记忆化搜索就可以解决了。
最后找方案的话暴力就可以,实际上还可以简化一下,ans^sg(i)^sg(j)^sg(k),也就是说消除i的影响再加上j和k的。
代码
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define N 10005 int T,n,ans; int p[30],a[30],sg[30]; int get_sg(int loc) { if (sg[loc]!=-1) return sg[loc]; int ans=0; bool ext[N*30];memset(ext,0,sizeof(ext)); for (int i=loc+1;i<=n;++i) for (int j=i;j<=n;++j) ext[get_sg(i)^get_sg(j)]=1; for (int i=0;;++i) if (!ext[i]) {sg[loc]=i;break;} return sg[loc]; } int main() { scanf("%d",&T); while (T--) { memset(sg,-1,sizeof(sg)); scanf("%d",&n);ans=0; for (int i=1;i<=n;++i) { scanf("%d",&p[i]); if (p[i]&1) ans^=get_sg(i); } if (ans) { int cnt=0; for (int i=1;i<=n;++i) if (p[i]) { for (int j=i+1;j<=n;++j) for (int k=j;k<=n;++k) { for (int l=1;l<=n;++l) a[l]=p[l]; --a[i];++a[j];++a[k]; int now=0; for (int l=1;l<=n;++l) if (a[l]&1) now^=get_sg(l); if (!now) { ++cnt; if (cnt==1) printf("%d %d %d\n",i-1,j-1,k-1); } } } printf("%d\n",cnt); } else { puts("-1 -1 -1"); puts("0"); } } }
相关文章推荐
- bzoj 1188 [HNOI2007]分裂游戏(SG函数,博弈)
- [SG函数] BZOJ1188: [HNOI2007]分裂游戏
- BZOJ 1188 [HNOI 2007]分裂游戏 (博弈)
- 【SG函数】BZOJ1188(HNOI2007)[分裂游戏]题解
- bzoj 1188 : [HNOI2007]分裂游戏 sg函数
- [BZOJ 1188] [HNOI2007] 分裂游戏 【博弈论|SG函数】
- bzoj 1188: [HNOI2007]分裂游戏 sg函数
- BZOJ 1188 [HNOI2007]分裂游戏 SG函数
- BZOJ1188 [HNOI2007]分裂游戏(SG函数)
- BZOJ1188 [HNOI2007]分裂游戏(SG函数)
- 【博弈论】【SG函数】【枚举】bzoj1188 [HNOI2007]分裂游戏
- bzoj 1188: [HNOI2007]分裂游戏(sg函数)
- [BZOJ1188][HNOI2007]分裂游戏(SG函数)
- BZOJ 1188 [HNOI2007]分裂游戏
- bzoj1188 [HNOI2007]分裂游戏
- bzoj 1188 [HNOI2007]分裂游戏
- BZOJ 1188 [HNOI2007]分裂游戏
- BZOJ 1188 [HNOI2007]分裂游戏
- BZOJ1188 [HNOI2007]分裂游戏(SG定理)
- BZOJ 1188: [HNOI2007]分裂游戏(multi-nim)