bzoj 4589 Hard Nim——FWT
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4589
一开始异或和为0的话先手必败。有 n 堆,每堆可以填那些数,求最后异或和为0的方案数,就是一个快速幂的异或FWT。
注意快速幂的过程中对那些数组直接乘就行,不用总是FWT!!!
为什么比Zinn慢了1008ms?
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=5e4+5,mod=1e9+7; int n,m,pri[5200],cnt,len,inv; int f[N<<2],a[N<<2],b[N<<2]; bool vis[N]; int pw(int x,int k) {int ret=1;while(k){if(k&1)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1;}return ret;} void fwt(int *a,bool fx) { for(int R=2;R<=len;R<<=1) for(int i=0,m=R>>1;i<len;i+=R) for(int j=0;j<m;j++) { int x=a[i+j]+a[i+m+j],y=a[i+j]+mod-a[i+m+j]; a[i+j]=(ll)x*(fx?inv:1)%mod; a[i+m+j]=(ll)y*(fx?inv:1)%mod; } } void init() { for(int i=2;i<=50000;i++) { if(!vis[i])pri[++cnt]=i; for(int j=1;j<=cnt&&i*pri[j]<=50000;j++) { vis[i*pri[j]]=1; if(i%pri[j]==0)break; } } for(int i=1;i<=cnt;i++)f[pri[i]]=1; inv=pw(2,mod-2); } int main() { init(); while(scanf("%d%d",&n,&m)==2) { for(len=1;len<=m;len<<=1); a[0]=1;for(int i=1;i<len;i++)a[i]=0; for(int i=0;i<=m;i++)b[i]=f[i]; for(int i=m+1;i<len;i++)b[i]=0; fwt(a,0); fwt(b,0); while(n) { if(n&1) for(int i=0;i<len;i++)a[i]=(ll)a[i]*b[i]%mod; for(int i=0;i<len;i++)b[i]=(ll)b[i]*b[i]%mod; n>>=1; } fwt(a,1); printf("%d\n",a[0]); } return 0; }