【BZOJ4600】硬币游戏,博弈
2016-09-18 18:52
316 查看
传送门
思路:
考场爆零系列
因为当时博弈pi都不会,连SG函数是啥都不知道
![](https://img-blog.csdn.net/20160918182451291)
现在会了一点点博弈,来看一下
很快写出了10分(n<=16)做法……
orz Va爷的题解
感觉Va爷的博客思路讲的不是很清楚,昨天晚上想了很久,感觉有一个比较合适的解释
我们发现初始状态是可以分解成若干只有一个是反面朝上,即ai=1的状态
举例来说,对于样例
1001000010001011
这个状态的子状态就是1,0001,000000001,0000000000001,0000000000001,000000000000001和0000000000000001
类似分治子问题的思想
也就是说,如果我们当前从左向右扫到第i枚硬币为1(反面朝上),那么前面1~i-1的硬币都是0(正面朝上)
显然对[1,i]的硬币进行操作是对>i的硬币没有影响的
那我们把问题变成求”[1,i]区间中a[i]=1,其余为0”状态下的SG函数,状态表示为sg[i]
做完这个子状态后再继续往后扫,扫到j
我们就可以看成前面那个i的子状态已经解决了,那么状态肯定是”[1,j]区间中a[j]=1,其余为0”
这和上面是同一个问题
初始状态的SG函数就是这些子状态的异或和
那怎么求这些子状态的SG函数?
按照题目给出的规则暴力枚举p,q就可以了
比如说我们正在处理状态x
枚举某一后继状态x′i,其中x′i中要翻过来的硬币是x1,x2,x3,..xn
(显然这些硬币都是≤x的)
我们可以把这个状态表示为x′i={x1,x2,x3,..xn}
那么这又是最上面我们所说的拆分子状态了
即x′i={x1}∪{x2}∪{x3}∪..∪{xn}
sg[x′i]=sg[x1] xor sg[x2] xor .. xor sg[xn]
枚举出x的所有后继状态,求出mex(最小未出现自然数)就是sg[x]啦
这里给出一个结论(仅面向初学者)
思路:
考场爆零系列
因为当时博弈pi都不会,连SG函数是啥都不知道
现在会了一点点博弈,来看一下
很快写出了10分(n<=16)做法……
orz Va爷的题解
感觉Va爷的博客思路讲的不是很清楚,昨天晚上想了很久,感觉有一个比较合适的解释
我们发现初始状态是可以分解成若干只有一个是反面朝上,即ai=1的状态
举例来说,对于样例
1001000010001011
这个状态的子状态就是1,0001,000000001,0000000000001,0000000000001,000000000000001和0000000000000001
类似分治子问题的思想
也就是说,如果我们当前从左向右扫到第i枚硬币为1(反面朝上),那么前面1~i-1的硬币都是0(正面朝上)
显然对[1,i]的硬币进行操作是对>i的硬币没有影响的
那我们把问题变成求”[1,i]区间中a[i]=1,其余为0”状态下的SG函数,状态表示为sg[i]
做完这个子状态后再继续往后扫,扫到j
我们就可以看成前面那个i的子状态已经解决了,那么状态肯定是”[1,j]区间中a[j]=1,其余为0”
这和上面是同一个问题
初始状态的SG函数就是这些子状态的异或和
那怎么求这些子状态的SG函数?
按照题目给出的规则暴力枚举p,q就可以了
比如说我们正在处理状态x
枚举某一后继状态x′i,其中x′i中要翻过来的硬币是x1,x2,x3,..xn
(显然这些硬币都是≤x的)
我们可以把这个状态表示为x′i={x1,x2,x3,..xn}
那么这又是最上面我们所说的拆分子状态了
即x′i={x1}∪{x2}∪{x3}∪..∪{xn}
sg[x′i]=sg[x1] xor sg[x2] xor .. xor sg[xn]
枚举出x的所有后继状态,求出mex(最小未出现自然数)就是sg[x]啦
这里给出一个结论(仅面向初学者)
一个状态的SG=它的所有后继状态的SG的mex=它的所有子状态的SG的异或和
代码:#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; int T,n,maxn; int sg[21][30005],a[30005]; bool b[55]; void dp(int y) { if (sg[maxn][y]!=-1) return; memset(b,0,sizeof(b)); int ta=0,tb=0,tc=y,tt,ty; for (;tc%2==0;tc/=2) ++ta; for (;tc%3==0;tc/=3) ++tb; for (int q=1;q<=maxn;++q) for (int p=1;p*q<=ta;++p) { tt=y;ty=-1; for (int j=0;j<=q;++j) { if (tt==y) ty=0; else ty=(ty==-1?sg[maxn][tt]:ty^sg[maxn][tt]); for (int k=1;k<=p;++k) tt/=2; } if (ty!=-1) b[ty]=1; } for (int q=1;q<=maxn;++q) for (int p=1;p*q<=tb;++p) { tt=y;ty=-1; for (int j=0;j<=q;++j) { if (tt==y) ty=0; else ty=(ty==-1?sg[maxn][tt]:ty^sg[maxn][tt]); for (int k=1;k<=p;++k) tt/=3; } if (ty!=-1) b[ty]=1; } for (int i=0;i<55;++i) if (!b[i]) return void(sg[maxn][y]=i); } main() { memset(sg,-1,sizeof(sg)); for (scanf("%d",&T);T;--T) { scanf("%d%d",&n,&maxn); int ans=0; for (int i=1;i<=n;++i) dp(i); for (int i=1;i<=n;++i) { scanf("%d",a+i); if (!a[i]) ans^=sg[maxn][i]; } if (ans) puts("win"); else puts("lose"); } }
相关文章推荐
- bzoj4600 [Sdoi2016]硬币游戏 sg函数+结论
- [bzoj4600][SDOI2016]硬币游戏
- bzoj4600 [Sdoi2016]硬币游戏
- bzoj4600 [Sdoi2016]硬币游戏
- 【bzoj4600】【SDOI2016】【硬币游戏】【博弈论+dp】
- Bzoj4600--Sdoi2016硬币游戏
- 【BZOJ 4600】【SDOI 2016】硬币游戏
- bzoj 4600 硬币游戏 博弈论
- 【bzoj 2017】硬币游戏
- [KMP 高斯消元] BZOJ 4820: [Sdoi2017]硬币游戏
- [bzoj 2017] [Usaco2009 Nov]硬币游戏
- [BZOJ2017] [Usaco2009 Nov]硬币游戏
- BZOJ 1115:[POI2009]石子游戏Kam 阶梯博弈
- bzoj1411: [ZJOI2009]硬币游戏
- [BZOJ1022][SHOI2008]小约翰的游戏John(博弈Anti-Nim游戏)
- [BZOJ4820][SDOI2017]硬币游戏(KMP+概率+高斯消元)
- SDOI2017 BZOJ 4820 硬币游戏 解题报告
- [BZOJ1188][HNOI2007]分裂游戏(博弈SG函数)
- [博弈论][阶梯博弈] BZOJ 1115:POI2009 石子游戏Kam
- bzoj 1188 [HNOI2007]分裂游戏(SG函数,博弈)