可以将问题转化成这样一个问题:选出一些数
a
1
,
a
2
,
…
,
a
m
a_1,a_2,\dots,a_m
a1,a2,…,am,使得存在这样的
x
1
,
x
2
,
…
,
x
m
x_1,x_2,\dots,x_m
x1,x2,…,xm满足
∑
i
=
1
m
a
i
x
i
≡
w
(
m
o
d
p
)
\sum_{i=1}^ma_ix_i\equiv w\pmod p
∑i=1maixi≡w(modp)
显然需要满足的条件就是
g
c
d
(
a
1
,
a
2
,
…
,
a
m
,
p
)
∣
w
gcd(a_1,a_2,\dots,a_m,p)|w
gcd(a1,a2,…,am,p)∣w,这个可以用类似于扩展欧几里得的方法证明。
那么,我们求出总共
m
m
m个
p
p
p的约数,分别为
b
1
,
b
2
,
…
,
b
m
b_1,b_2,\dots,b_m
b1,b2,…,bm。令
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前
i
i
i个约数中选取若干个最后的
g
c
d
gcd
gcd为第
j
j
j个约数的方案数。
转移比较简单,
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
+
(
[
i
=
=
j
]
+
∑
k
[
g
c
d
(
b
[
i
]
,
b
[
k
]
)
=
=
b
[
j
]
]
f
[
i
−
1
]
[
k
]
)
×
(
2
∣
s
[
i
]
∣
−
1
)
f[i][j]=f[i-1][j]+([i==j]+\sum_k[gcd(b[i],b[k])==b[j]]f[i-1][k])\times(2^{|s[i]|}-1)
f[i][j]=f[i−1][j]+([i==j]+∑k[gcd(b[i],b[k])==b[j]]f[i−1][k])×(2∣s[i]∣−1)。具体实现的时候可以枚举
k
k
k,那么
j
j
j自然也得出来了。
然后考虑最后的答案怎么处理,令
g
[
i
]
g[i]
g[i]表示所有约数中选择若干个约数使得
g
c
d
gcd
gcd为第
i
i
i个约数的约数的方案数,那么显然有
g
[
i
]
=
∑
b
[
j
]
∣
b
[
i
]
f
[
n
]
[
j
]
g[i]=\sum_{b[j]|b[i]}f[n][j]
g[i]=∑b[j]∣b[i]f[n][j]
那么,现在对于某一个询问
w
w
w,答案显然为
g
[
n
u
m
[
g
c
d
(
w
,
p
)
]
]
g[num[gcd(w,p)]]
g[num[gcd(w,p)]]
时间复杂度:
O
(
p
+
m
2
log
p
+
q
)
O(\sqrt p+m^2\log p+q)
O(p+m2logp+q)
m
m
m大概在
2
×
1
0
3
2×10^3
2×103左右,可以通过此题。
代码
#include<bits/stdc++.h>usingnamespace std;template<typename T>voidchkmax(T &x, T y){x = x > y ? x : y;}template<typename T>voidchkmin(T &x, T y){x = x < y ? x : y;}template<typename T>voidread(T &x){
x =0;int f =1;char c =getchar();while(!isdigit(c)){if(c =='-') f =-1; c =getchar();}while(isdigit(c)) x = x *10+ c -'0', c =getchar(); x *= f;}constint N =1000010, M =2010, Mod =1e9+7;int a[N], b[N], g[N], pw[N], sum[N], f[M][M];intgcd(int x,int y){return y ?gcd(y, x % y): x;}voidadd(int&x,int y){x += y;if(x >= Mod) x -= Mod;}intmain(){int n, q, p, m =0;read(n),read(q),read(p);for(int i =1; i <= n; i++)read(a[i]), a[i]=gcd(a[i], p);for(int i =1; i * i <= p; i++)if(p % i ==0){
b[++m]= i;if(i * i != p) b[++m]= p / i;}sort(b +1, b + m +1); pw[0]=1;for(int i =1; i <= n; i++) pw[i]=2ll* pw[i -1]% Mod;for(int i =1; i <= n; i++){
a[i]=lower_bound(b +1, b + m +1, a[i])- b;
sum[a[i]]++,add(pw[i], Mod -1);}
pw[0]=0;for(int i =1; i <= m; i++){for(int j =1; j <= m; j++) f[i][j]= f[i -1][j];for(int j =1; j <= m; j++){int k =gcd(b[i], b[j]); k =lower_bound(b +1, b + m +1, k)- b;add(f[i][k],1ll* f[i -1][j]* pw[sum[i]]% Mod);}add(f[i][i], pw[sum[i]]);}for(int i =1; i <= m; i++)for(int j =1; j <= m; j++)if(b[i]% b[j]==0)add(g[i], f[m][j]);while(q--){int x;read(x);int y =gcd(x, p); y =lower_bound(b +1, b + m +1, y)- b;
cout << g[y]<<"\n";}return0;}