bzoj4589-Hard Nim【FWT】
阿新 • • 發佈:2021-01-12
正題
題目連結:https://darkbzoj.tk/problem/4589
題目大意
求有多少個長度為\(n\)的數列滿足它們都是不大於\(m\)的質數且異或和為\(0\)。
解題思路
兩個初始多項式\(F[0]=1\),\(G[prime\leq m]=1\),然後答案就是\(F\ xor\ G^n\)。然後\(\text{FWT}\)之後點值快速冪就好了。
時間複雜度\(O(n\log n)\)
\(\color{white}{寫水題有助於背板}\)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=(1<<16)+10,P=1e9+7,inv2=(P+1)/2; ll n,k,m,f[N],g[N]; bool v[N]; void FWT(ll *f,ll op){ if(op==-1)op=inv2; for(ll p=2;p<=n;p<<=1) for(ll k=0,len=p>>1;k<n;k+=p) for(ll i=k;i<k+len;i++){ ll x=f[i],y=f[i+len]; f[i]=(x+y)*op%P; f[i+len]=(x-y+P)*op%P; } return; } signed main() { while(scanf("%lld%lld",&k,&m)!=EOF){ memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); memset(v,0,sizeof(v)); n=1; while(n<=m)n<<=1; for(ll i=2;i<=m;i++){ if(!v[i]){ f[i]=1; for(ll j=i;j<=m;j+=i) v[j]=1; } } g[0]=1; FWT(g,1);FWT(f,1); while(k){ if(k&1){ for(ll i=0;i<n;i++) g[i]=g[i]*f[i]%P; } for(ll i=0;i<n;i++) f[i]=f[i]*f[i]%P; k>>=1; } FWT(g,-1); printf("%lld\n",g[0]); } return 0; }