【BZOJ5302】【HAOI2018】—奇怪的背包(裴蜀定理+dp)
题意:求满足的个数
只把是否取看做2种不同情况
考虑裴蜀定理有解当且仅当
把看做,那么显然有解得保证
因为以内因子个数最多也只有
那我们可以枚举的因数求方案
表示前个因子,凑出第个因子的方案数
暴力转移即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
return res*f;
}
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
const ll mod=1e9+7;
const int N=1000006;
const int M=50004;
int n,p,q;
int v[N],w[N],tot;
ll f[2][M],g[M],d[N],fac[N],ans[M];
inline int find(ll x){
if(x*x<=p)return d[x];
return d[p/x]+1;
}
int main(){
n=read(),q=read(),p=read();
for(ll i=1;i*i<=p;i++){
if(p%i==0){
fac[++tot]=i;
d[i]=tot;
if(i*i!=p)fac[++tot]=p/i;
}
}
for(int i=1;i<=n;i++){
int x=read();
x=gcd(p,x);
if(!g[find(x)])g[find(x)]=2;
else (g[find(x)]*=2)%=mod;
}
int now=1,past=0;
f[past][find(p)]=1;
for(int i=1;i<=tot;i++){
memset(f[now],0,sizeof(f[now]));
if(!g[i])g[i]=1;
for(int j=1;j<=tot;j++){
int x=find(gcd(fac[i],fac[j]));
(f[now][j]+=f[past][j])%=mod;
(f[now][x]+=f[past][j]*(g[i]-1)%mod)%=mod;
}
swap(now,past);
}
for(int i=1;i<=tot;i++){
for(int j=1;j<=tot;j++){
if(fac[i]%fac[j]==0)(ans[i]+=f[past][j])%=mod;
}
}
for(int i=1;i<=q;i++){
int x=read();
x=gcd(x,p);
if(x!=p)cout<<ans[find(x)]<<'\n';
else cout<<ans[find(x)]-1<<'\n';
}
}