bzoj 4589: Hard Nim

Description

Claris和NanoApe在玩石子游戏,他们有n堆石子,规则如下:

  1. Claris和NanoApe两个人轮流拿石子,Claris先拿。
  2. 每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜。
    不同的初始局面,决定了最终的获胜者,有些局面下先拿的Claris会赢,其余的局面Claris会负。
    Claris很好奇,如果这n堆石子满足每堆石子的初始数量是不超过m的质数,而且他们都会按照最优策略玩游戏,那么NanoApe能获胜的局面有多少种。
    由于答案可能很大,你只需要给出答案对10^9+7取模的值。

Solution

这是普通的 \(nim\) 游戏,异或和为 \(0\) 即先手必败,那么就可以 \(DP\) 求解了
\(f[i][j]\) 表示前 \(i\) 堆,异或和为 \(j\) 的方案数
那么 \(f[i][j]=\sum f[i-1][p]*f[i-1][q]\,\,p⊕q=j\)
直接 \(FWT\) 优化一下就好了
\(n\) 比较大,用快速幂做一下就行了,注意 \(FWT\) 要写在快速幂外面,快速幂中做点值运算复杂度才对

#include<bits/stdc++.h>
using namespace std;
const int N=100010,mod=1e9+7,inv=500000004;
int k,n,m;bool vis[N];
inline void priwork(){
	for(int i=2;i*i<=50000;i++){
		if(vis[i])continue;
		for(int j=i*i;j<=50000;j+=i)vis[j]=1;
	}vis[0]=vis[1]=1;
}
inline void fwt(int *A,int o){
	for(int i=1;i<n;i<<=1)
		for(int j=0;j<n;j+=i<<1)
			for(int k=0;k<i;k++){
				int x=A[j+k],y=A[j+k+i];
				if(!o)A[j+k]=(x+y)%mod,A[j+k+i]=(x-y+mod)%mod;
				else A[j+k]=1ll*(x+y)*inv%mod,A[j+k+i]=1ll*(x-y+mod)*inv%mod;
			}
}
int a[N],b[N];
inline void work(){
	for(n=1;n<=m;n<<=1);
	for(int i=0;i<=m;i++)a[i]=vis[i]^1;
	b[0]=1;
	fwt(a,0);fwt(b,0);
	while(k){
		if(k&1)for(int i=0;i<=n;i++)b[i]=1ll*b[i]*a[i]%mod;
		for(int i=0;i<=n;i++)a[i]=1ll*a[i]*a[i]%mod;k>>=1;
	}
	fwt(b,1);
	printf("%d\n",b[0]);
	for(int i=0;i<=n;i++)a[i]=b[i]=0;
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  priwork();
  while(~scanf("%d%d",&k,&m))work();
  return 0;
}

posted @ 2018-07-15 11:25  PIPIBoss  阅读(116)  评论(0编辑  收藏  举报