bzoj千题计划308:bzoj4589: Hard Nim(倍增FWT+生成函数)
https://www.lydsy.com/JudgeOnline/problem.php?id=4589
n*m*m 做法
dp[i][j] 前i堆石子,异或和为j的方案数
第一重循环可以矩阵快速幂优化
后面求出序列的生成函数可以FWT优化
做log次FWT也很慢(logn*m*logm)
两个合并就是倍增FWT,即先对生成函数的序列做一次正变换,对正变换得到的每个结果快速幂,最后逆变换回去
时间复杂度O(logn*m+m*logm)
生成函数:是质数则系数为1,否则为0
#include<cstdio> #include<cstring> using namespace std; #define N 50001 const int mod=1e9+7; const int M=1<<16; int inv; int a[N]; int b[M+1]; void FWT(int *a,int n) { int x,y; for(int d=1;d<n;d<<=1) for(int m=d<<1,i=0;i<n;i+=m) for(int j=0;j<d;++j) { x=a[i+j]; y=a[i+j+d]; a[i+j]=x+y; a[i+j+d]=x-y; a[i+j]-=a[i+j]>=mod ? mod : 0; a[i+j+d]+=a[i+j+d]<0 ? mod : 0; } } void IFWT(int *a,int n) { int x,y; for(int d=1;d<n;d<<=1) for(int m=d<<1,i=0;i<n;i+=m) for(int j=0;j<d;++j) { x=a[i+j]; y=a[i+j+d]; a[i+j]=1LL*(x+y)*inv%mod; a[i+j+d]=1LL*(x-y+mod)%mod*inv%mod; } } int Pow(int a,int b) { int res=1; for(;b;a=1LL*a*a%mod,b>>=1) if(b&1) res=1LL*res*a%mod; return res; } int main() { for(int i=2;i<N;++i) a[i]=1; for(int i=2;i<N;++i) if(a[i]) for(int j=2;i*j<N;++j) a[i*j]=0; inv=Pow(2,mod-2); int n,m; int len; while(scanf("%d%d",&n,&m)!=EOF) { memset(b,0,sizeof(b)); for(int i=1;i<=m;++i) b[i]=a[i]; len=1; while(len<=m) len<<=1; FWT(b,len); for(int i=0;i<len;++i) b[i]=Pow(b[i],n); IFWT(b,len); printf("%d\n",b[0]); } }