题意
考虑(n=1)的情况,我们由裴蜀定理可知,(k*a_1\%P)能表示(gcd(a_1,P))的所有倍数。
扩展到多个数也是同理(不会证):
((k_1a_1+k_2a_2+...+k_na_n)\%P)能表示出(gcd(a_1,a_2,...,a_n))的所有倍数。
于是令(v_i=gcd(v_i,P))后问题是等价的。
之后处理出(P)的所有约数,假设数量为(m),存在(a)数组中。
设(f_{i,j})表示考虑(P)的前(i)个约数,取出的数的(gcd)为(a_j)的方案数,(cnt_i)表示(a_i)这个约数在(v)(取过(gcd)的)中出现的次数。
(f_{i,k}+=f_{i-1,j}*(2^{cnt_i}-1))
(f_{i,i}+=2^{cnt_i}-1)
之后对于每个(w_i),我们枚举它的约数:
(ans=sumlimits_{a_i|w}f_{n,i})。
但这样询问(mq)的,我们要进一步优化:
发现(a_i)也是(P)的约数,所以(a_i|(gcd(P,w))),因此可以使(w=gcd(w,P))。
我们预处理(g_i=sumlimits_{a_j|a_i}f_{n,j}),这样就可以(O(1))处理每次询问了。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
const int maxm=5e4+10;
const int mod=1e9+7;
int n,m,P,Q;
int a[maxm],val[maxn],cnt[maxm],pw[maxn],g[maxm];
int f[2][maxm];
int main()
{
scanf("%d%d%d",&n,&Q,&P);
for(int i=1;i<=n;i++)scanf("%d",&val[i]),val[i]=__gcd(val[i],P);
for(int i=1;i*i<=P;i++)
{
if(P%i)continue;
a[++m]=i;
if(P!=i*i)a[++m]=P/i;
}
sort(a+1,a+m+1);
for(int i=1;i<=n;i++)cnt[lower_bound(a+1,a+m+1,val[i])-a]++;
pw[1]=2;
for(int i=2;i<=n;i++)pw[i]=1ll*pw[i-1]*2%mod;
for(int i=1;i<=n;i++)pw[i]=(pw[i]-1+mod)%mod;
for(int i=1;i<=m;i++)
{
int now=i&1;
for(int j=1;j<=m;j++)f[now][j]=f[now^1][j];
for(int j=1;j<i;j++)
{
int k=__gcd(a[i],a[j]);
k=lower_bound(a+1,a+m+1,k)-a;
f[now][k]=(f[now][k]+1ll*f[now^1][j]*pw[cnt[i]]%mod)%mod;
}
f[now][i]=(f[now][i]+pw[cnt[i]])%mod;
}
for(int i=1;i<=m;i++)
for(int j=1;j<=i;j++)
if(a[i]%a[j]==0)g[i]=(g[i]+f[m&1][j])%mod;
while(Q--)
{
int k;scanf("%d",&k);
k=__gcd(k,P);
printf("%d
",g[lower_bound(a+1,a+m+1,k)-a]);
}
return 0;
}