BZOJ传送门
洛谷传送门
解析:
熟悉 e x g c d exgcd exgcd的人都知道这道题的结论。。。
每一个 v i v_i vi等价于 g c d ( v i , P ) gcd(v_i,P) gcd(vi,P)
最后要求的 w w w在模意义下实际上就是 g c d ( w , P ) gcd(w,P) gcd(w,P)
用
O
(
P
)
O(\sqrt P)
O(P)时间处理出所有
P
P
P的约数就能愉快地水过了 。
当然还是讲一下怎么做。
以下的 v i v_i vi和 w w w均是取了 g c d gcd gcd之后的。
由裴蜀定理,最后选择的 v i v_i vi要能够凑出 w w w,需要满足 gcd i = 1 t ( v i ) ∣ w \gcd\limits_{i=1}^t(v_i)\mid w i=1gcdt(vi)∣w。
所以只需要预处理出最终 g c d gcd gcd等于每个约数的方案数就行了。
同时统计一下每个约数的因数前缀和
预处理复杂度大概是 O ( σ ( P ) 2 ) = O ( P 2 3 ) O(\sigma(P)^2)=O(P^{\frac{2}{3}}) O(σ(P)2)=O(P32)
然后就可以 O ( 1 ) O(1) O(1)回答每个询问了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
struct Map{
cs static int magic=189859;
int key[magic],val[magic];
Map(){memset(key,-1,sizeof key);};
cs int &operator[](cs int &k)cs{
int h=k%magic;
while((~key[h])&&(key[h]^k))h=(h+1)%magic;
return val[h];
}
int &operator[](cs int &k){
int h=k%magic;
while((~key[h])&&(key[h]^k))h=(h+1)%magic;
if(key[h]^k)key[h]=k;
return val[h];
}
}id;
cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(int a,int b){return a<b?a-b+mod:a-b;}
inline int mul(int a,int b){return (ll)a*b%mod;}
cs int N=1e6+6,M=1e5+5;
int n,q,P;
int v[N];
int factor[M],fcnt,cnt[M];
int f[M],now;
int ans[M];
int pow2[N],sum[N];
inline void sieve(){
for(int re i=1;(ll)i*i<=P;++i)if(P%i==0)factor[id[i]=++fcnt]=i;
for(int re i=fcnt;i;--i)if(P/factor[i]!=factor[i])factor[id[P/factor[i]]=++fcnt]=P/factor[i];
}
inline int gcd(int a,int b){
if(!a||!b)return a|b;
re int shift=__builtin_ctz(a|b);
for(b>>=__builtin_ctz(b);a;a-=b)if((a>>=__builtin_ctz(a))<b)swap(a,b);
return b<<shift;
}
inline void init(){
for(int re i=1;i<=n;++i)++cnt[id[gcd(v[i],P)]];
pow2[0]=1;
for(int re i=1;i<=n;++i)pow2[i]=mul(2,pow2[i-1]);
for(int re i=1;i<=n;++i)pow2[i]=dec(pow2[i],1);
for(int re i=1;i<=fcnt;++i)if(cnt[i]){
for(int re j=1;j<=fcnt;++j)if(f[j]){
int nxt=gcd(factor[i],factor[j]);
int pos=id[nxt];
f[pos]=add(f[pos],mul(f[j],pow2[cnt[i]]));
}
f[i]=add(f[i],pow2[cnt[i]]);
}
for(int re i=fcnt;i;--i)
for(int re j=i-1;j;--j)if(factor[i]%factor[j]==0)f[i]=add(f[i],f[j]);
}
signed main(){
n=getint();q=getint();P=getint();
sieve();
for(int re i=1;i<=n;++i)v[i]=getint();
init();
while(q--)cout<<f[id[gcd(getint(),P)]]<<"\n";
return 0;
}