题目
筛出(L)的每个质因子,限制条件实际上就是限制了每个质因子的出现次数([l,r]),且(l,r)都有正好取到的。
显然(L)最多有(8)个不同的因子,所以对每个数而言,我们对其每个质因子是否取到(l)或(r)状压,这样([1,n])的数就可以表示成一个(16)位的二进制数。
那么我们要求的就是在强制选某个二进制数的情况下,选出一些二进制数使得其按位或为全集的方案数。
令(f(S))表示选出一些二进制数使得其按位或为(S)的方案数。
考虑容斥,设(g(S)=sumlimits_{Tsubseteq S}f(T))。
那么显然的,记(cnt_S)表示有多少个二进制数是(S)的子集,(g(S)=2^{cnt_S})。
那么我们容斥即可得到(f(S)=sumlimits_{Tsubseteq S}(-1)^{|S|-|T|}g(T))。
然后考虑计算强制选择某个二进制数时的答案。
设这个数为(T),其补集为(S)。
那么我们需要枚举的就是(S)的超集(即子集包含(S)的集合)。
这个可以转化为枚举(S)的子集,然后枚举的超集就是(Tcup S)。
加上记忆化之后复杂度为(3^{16})。
#include<bits/stdc++.h>
#define pi pair<int,int>
#define pb push_back
#define fi first
#define se second
#define count __builtin_popcount
using namespace std;
const int N=100007,P=1000000007;
namespace IO
{
char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[11],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
void Put(char x){*oS++=x;if(oS==oT)Flush();}
//int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
void write(int x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('
');}
}
using namespace IO;
int read(){int x;cin>>x;return x;}
int inc(int a,int b){a+=b;return a>=P? a-P:a;}
int dec(int a,int b){a-=b;return a<0? a+P:a;}
int mul(int a,int b){return 1ll*a*b%P;}
int n,G,L,Q,l[N],r[N],p2[N],sz[N],U,len,ans[1<<17];vector<pi>fac;unordered_map<int,int>mp;
int GetS(int x)
{
int S=0,i,cnt;
for(i=0;i<len;++i)
{
for(cnt=0;!(x%fac[i].fi);++cnt) x/=fac[i].fi;
S|=(cnt==l[i])<<i|(cnt==r[i])<<i+len;
}
return S;
}
void initfac(int x=L)
{
for(int i=2,cnt=0;i*i<=x;++i)
if(!(x%i))
{
for(cnt=0;!(x%i);x/=i,++cnt);
fac.pb(pi(i,cnt));
}
if(x^1) fac.pb(pi(x,1));
}
void initpow()
{
p2[0]=1,len=fac.size(),U=(1<<len*2)-1;
for(int i=1;i<=U;++i) p2[i]=inc(p2[i-1],p2[i-1]);
}
void initlr()
{
for(int i=0,x;i<len;++i)
{
r[i]=fac[i].se;
for(x=G;!(x%fac[i].fi);++l[i]) x/=fac[i].fi;
}
}
void initagg()
{
for(int i=1;i*i<=L;++i)
if(!(L%i))
{
if(!(i%G)&&i<=n) mp[i]=GetS(i);
if(i*i^L&&!(L/i%G)&&L/i<=n) mp[L/i]=GetS(L/i);
}
len<<=1;
for(auto x:mp) ++sz[x.se];
for(int i=0,S;i<len;++i) for(S=0;S<=U;++S) if(S&1<<i) sz[S]+=sz[S^1<<i];
}
int solve(int x)
{
int T=mp[x],S=U^T,sum=count(T)&1? (P-p2[sz[T]-1]):(p2[sz[T]-1]);
if(ans[T]) return ans[T];
for(int s=S;s;s=s-1&S)
if(count(s|T)&1) sum=dec(sum,p2[sz[s|T]-1]);
else sum=inc(sum,p2[sz[s|T]-1]);
return ans[T]=sum;
}
int main()
{
n=read(),G=read(),L=read(),Q=read();
if(L%G) { while(Q--) puts("0"); return 0; }
initfac(),initpow(),initlr(),initagg();
for(int x;Q;--Q) x=read(),write(x%G||L%x||x>n? 0:solve(x));
return Flush(),0;
}