就是转化成求一堆数gcd的常用套路:考虑最小最大次幂
然后状压DP,
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示到第i个,状态为j这里最多600种转移,可以直接爆搜
如果我们正着DP一遍,反着DP一遍,那么合并就是or卷积:在正反中任意一个出现的必须保留
最后做一遍andfwt来回答询问
Code:
#include<bits/stdc++.h>
#define ll long long
#define db double
#define pb push_back
#define mod 1000000007
#define inv2 500000004
using namespace std;
inline int read(){
int res=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
return res*f;
}
inline int add(int x,int y){x+=y;if(x>=mod) x-=mod;return x;}
inline int dec(int x,int y){x-=y;if(x<0) x+=mod;return x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void inc(int &x,int y){x+=y;if(x>=mod) x-=mod;}
inline void Dec(int &x,int y){x-=y;if(x<0) x+=mod;}
inline void Mul(int &x,int y){x=mul(x,y);}
inline int ksm(int a,int b){int res=1;for(;b;b>>=1,a=mul(a,a)) if(b&1) res=mul(res,a);return res;}
const int N=1e4+5,State=1<<16,M=600;
inline void fwt_or(int *a,int n,int kd){
for(int i=1;i<n;i<<=1)
for(int p=i<<1,j=0;j<n;j+=p)
for(int k=0;k<i;++k)
inc(a[i+j+k],kd==1?a[j+k]:dec(0,a[j+k]));
}
inline void fwt_and(int *a,int n,int kd){
for(int i=1;i<n;i<<=1)
for(int p=i<<1,j=0;j<n;j+=p)
for(int k=0;k<i;++k)
inc(a[j+k],kd==1?a[i+j+k]:dec(0,a[i+j+k]));
}
int pri[N],pt[N],cnt=0;
inline void init(int n){
pt[1]=1;
for(int i=2;i<=n;++i){
if(!pt[i]) pri[++cnt]=i;
for(int j=1;j<=cnt && i*pri[j]<=n;j++){
pt[i*pri[j]]=1;
if(i%pri[j]==0) break;
}
}
}
int lim[N],tot=0,pr[N];
inline void divide(int x){
for(int i=1;i<=cnt && pri[i]*pri[i]<=x;++i){
if(x%pri[i]==0){
pr[++tot]=pri[i];
while(x%pri[i]==0) x/=pri[i],++lim[tot];
}
}
if(x>1) pr[++tot]=x,lim[tot]=1;
}
int trans[State];
int n,G,L;
void dfs(int v,int mlti,int S1,int S2){
if(v==tot+1){++trans[S1|(S2<<tot)];return;}
for(int i=0;i<=lim[v];++i){
dfs(v+1,mlti,S1|((i==0)<<(v-1)),S2|((i==lim[v])<<(v-1)));
if(1ll*mlti*pr[v]>n) return;
mlti*=pr[v];
}
}
inline int get(int x){
int res=0;
for(int i=1;i<=tot;++i){
int cnt=0;
while(x%pr[i]==0) x/=pr[i],++cnt;
if(cnt==0) res|=(1<<(i-1));
if(cnt==lim[i]) res|=(1<<(i-1+tot));
}
return res;
}
int f[M][State],g[M][State];
int dp[State],tmp[State];
int state[State],gcnt[State],scnt=0;
int main(){
n=read();G=read();L=read();init(10000);
int q=read();
if(L%G){while(q--) puts("0");return 0;}
L/=G,n/=G;divide(L);dfs(1,1,0,0);
int all=1<<(tot*2);
for(int i=0;i<all;++i) if(trans[i]) state[++scnt]=i,gcnt[scnt]=ksm(2,trans[i])-1;
memcpy(trans,gcnt,sizeof(gcnt));
f[0][0]=1;dp[0]=1;
for(int i=1;i<=scnt;++i){
for(int j=0;j<all;++j) inc(tmp[state[i]|j],mul(dp[j],trans[i]));
for(int j=0;j<all;++j) inc(dp[j],tmp[j]),tmp[j]=0;
for(int j=0;j<all;++j) f[i][j]=dp[j];
}
memset(dp,0,sizeof(dp));
g[scnt+1][0]=1;dp[0]=1;
for(int i=scnt;i;i--){
for(int j=0;j<all;++j) inc(tmp[state[i]|j],mul(dp[j],trans[i]));
for(int j=0;j<all;++j) inc(dp[j],tmp[j]),tmp[j]=0;
for(int j=0;j<all;++j) g[i][j]=dp[j];
}
for(int i=0;i<=scnt;++i) fwt_or(f[i],all,1);
for(int i=1;i<=scnt+1;++i) fwt_or(g[i],all,1);
for(int i=0;i<=scnt;++i)
for(int j=0;j<all;++j)
f[i][j]=mul(f[i][j],g[i+2][j]);
for(int i=0;i<=scnt;++i) fwt_or(f[i],all,-1),fwt_and(f[i],all,1);
while(q--){
int x=read();
if(x%G){puts("0");continue;}
x/=G;
if(L%x || x>n) {puts("0");continue;}
int d=get(x),ans=0;
int p=lower_bound(state+1,state+scnt+1,d)-state-1;
ans=f[p][(all-1)^d];
Mul(ans,(trans[p+1]+1));
cout<<mul(ans,inv2)<<"\n";
}
return 0;
}