Description
(n) 种权值各不相同的物品,每种无穷个,给定数 (P)。(q) 次询问,每次问有多少种选物品的方案(每种任意个),使得在模 (P) 意义下同余于 (w)。方案不同当且仅当物品种类不同。
Solution
容易知道(考虑裴蜀定理),对于一种价值为 (v) 的物品,使用无穷次后,得到的值只会是
[0,gcd(v,P),2gcd(v,P),3gcd(v,P),dots
]
所以考虑直接将 (v) 变为 (gcd(P,v))。进一步(多个数的裴蜀定理),对于多种物品,能凑出来的值有
[0,gcd(v_1,v_2,dots),2gcd(v_1,v_2,dots),3gcd(v_1,v_2,dots),dots
]
所以方案合法当且仅当 (gcd(v_1,v_2,dots)|w)
容易发现 (gcd) 只会取 (P) 的约数,所以考虑算每种约数有多少种方案可以凑出。用 (dp[i][j]) 表示考虑了前 (i) 个约数,(gcd) 是第 (j) 个约数的方案。转移就很显然。
算答案只需要枚举 (w) 的约数即可。但这样还是不够优秀。容易发现最终的答案其实是 (w) 和 (P) 的高维前缀的交集。这个交集部分其实就是 (gcd(w,P)),而这一定是 (P) 的约数。所以可以考虑预处理高维前缀和。
int main(){
int n=read(),Q=read(),P=read(); pw[0]=1;
for(int i=1;i*i<=P;i++)
if(P%i==0){ p[++cnt]=i; if(i*i!=P) p[++cnt]=P/i;}
sort(p+1,p+1+cnt); for(int i=1;i<=n;i++) pw[i]=pw[i-1]*2ll%Mod;
for(int i=1;i<=n;i++)
a[i]=gcd(read(),P),c[Get(a[i])]++;
for(int i=1;i<=cnt;i++){
for(int k=1;k<=cnt;k++){
int &x=dp[Get(gcd(p[i],p[k]))];
x=(x+1ll*dp[k]*(pw[c[i]]-1)%Mod)%Mod;
}
dp[i]=(dp[i]+pw[c[i]]-1)%Mod;
}
for(int i=cnt;i;i--)
for(int j=1;j<i;j++)
if(p[i]%p[j]==0) dp[i]=(dp[i]+dp[j])%Mod;
while(Q--) printf("%d
",dp[Get(gcd(P,read()))]);
}