bzoj 5019: [Snoi2017]遺失的答案【dp+FWT】
阿新 • • 發佈:2018-12-01
滿足GL的組合一定包含GL每個質因數最大次冪個最小次冪,並且能做限制這些數不會超過600個
然後質因數最多8個,所以可以狀壓f[s1][s2]為選s1集合滿足最大限制選s2集合滿足最小限制
dfs一下預處理出質因數只選一個質因數的初始狀態
然後dp,做一個字首一個字尾,設f[i][j]為前i個質因數選成集合j的方案數,g[i][j]為後i個質因數選成集合j的方案數,然後轉移很好想,就是f[i][va[i]|j]+=f[i-1][j]*rs[i],其中rs是滿足第i個質因數的方案數,g同理
然後我們需要合併出來一個“空出一個數”這樣的東西來回答詢問,合併的時候用orFWT即可
包含集合s的方案數也加到s的方案數裡,就是andFWT的正變換部分,這樣統計答案的時候就不用跑一遍了
然後回答的時候就是統計一下x極大極小質因數次冪的貢獻然後直接查空出來這個集合的部分,最後乘上這個集合的選區方案數即可
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=100005,mod=1000000007,inv2=500000004; int n,G,L,q,lm,p[N],tot,si[N],s[N],rs[N],va[N],con,f[605][70005],g[605][70005]; bool v[N]; int read() { int r=0,f=1; char p=getchar(); while(p>'9'||p<'0') { if(p=='-') f=-1; p=getchar(); } while(p>='0'&&p<='9') { r=r*10+p-48; p=getchar(); } return r*f; } void jia(int &x,int y) { x+=y; (x>=mod)?x-=mod:0; } void jian(int &x,int y) { x-=y; (x<0)?x+=mod:0; } void dfs(int w,long long v,int s1,int s2) { if(w==tot+1) { s[s1|(s2<<tot)]++; return; } for(int i=0;i<=si[w];i++) { dfs(w+1,v,s1|((i==0)<<(w-1)),s2|((i==si[w])<<(w-1))); v*=p[w]; if(v>n) break; } } int ksm(int a,int b) { int r=1; while(b) { if(b&1) r=1ll*r*a%mod; a=1ll*a*a%mod; b>>=1; } return r; } void fwtor(int a[],int f) { for(int i=1;i<lm;i<<=1) for(int j=0;j<lm;j+=(i<<1)) for(int k=0;k<i;k++) { if(f==1) jia(a[i+j+k],a[j+k]); else jian(a[i+j+k],a[j+k]); } } void fwtand(int a[],int f) { for(int i=1;i<lm;i<<=1) for(int j=0;j<lm;j+=(i<<1)) for(int k=0;k<i;k++) { if(f==1) jia(a[j+k],a[i+j+k]); else jian(a[j+k],a[i+j+k]); } } int main() { n=read(),G=read(),L=read(),q=read(); if(L%G) { while(q--) puts("0"); return 0; } L/=G,n/=G; int x=L; for(int i=2;i*i<=L;i++) if(x%i==0) { p[++tot]=i; while(x%i==0) si[tot]++,x/=i; } if(x>1) p[++tot]=x,si[tot]=1; dfs(1,1,0,0); int ss=(1<<(tot*2)); for(int i=0;i<ss;i++) if(s[i]) va[++con]=i,rs[con]=ksm(2,s[i])-1; f[0][0]=1; for(int i=1;i<=con;i++) { for(int j=0;j<ss;j++) jia(f[i][va[i]|j],1ll*f[i-1][j]*rs[i]%mod); for(int j=0;j<ss;j++) jia(f[i][j],f[i-1][j]); } g[con+1][0]=1; for(int i=con;i>=1;i--) { for(int j=0;j<ss;j++) jia(g[i][va[i]|j],1ll*g[i+1][j]*rs[i]%mod); for(int j=0;j<ss;j++) jia(g[i][j],g[i+1][j]); } lm=ss; for(int i=0;i<=con;i++) fwtor(f[i],1); for(int i=1;i<=con+1;i++) fwtor(g[i],1); for(int i=0;i<=con;i++) for(int j=0;j<ss;j++) f[i][j]=1ll*f[i][j]*g[i+2][j]%mod; for(int i=0;i<=con;i++) fwtor(f[i],-1),fwtand(f[i],1); // for(int i=0;i<=con;i++) // { // for(int j=0;j<ss;j++) // cerr<<f[i][j]<<" "; // cerr<<endl; // } while(q--) { int x=read(),s=0; if(x%G||L%(x/G)||(x/G)>n) { puts("0"); continue; } x/=G; for(int i=1;i<=tot;i++) { int sm=0; while(x%p[i]==0) x/=p[i],sm++; if(sm==0) s|=(1<<(i-1)); if(sm==si[i]) s|=(1<<(i-1+tot)); } int w=lower_bound(&va[1],&va[con+1],s)-va-1;//cerr<<w<<endl; printf("%lld\n",((1ll*f[w][(ss-1)^s]*(rs[w+1]+1)%mod*inv2%mod)+mod)%mod); } return 0; }