對於給出來的一個揹包重量w,它能表示出來的是w和給定模數gcd的所有倍數。
即gcd(mod,w),2*gcd(mod,w),3*gcd(mod,w)……
可以從循環節的角度感性理解。
所以每一個數讀入時,可以先轉化成和模數的gcd。然後能表示出所有它倍數的重量。
所以我們選出來的揹包加上模數的總gcd,應該是w的約數。這樣才能表示出它來。(反正模數可以視作一個揹包)
然而模數的約數又只有那麼一兩千個。所以我們大可以求出來,然後考慮動態規劃。(現在有兩個範圍在兩千左右的數列可以n方了)
令表示考慮到第i種揹包,和模數的gcd是j(這裏指第j個模數的約數(開個map就是了))。枚舉第i個揹包是否選擇,我們可以得到兩個轉移。一是繼承上一種,二是選擇當前數,gcd會變化,加進去(見代碼)。
爲什麼要用種呢,因爲n有一百萬,但我們只需要考慮不同的兩千個約數。對於每一個約數,可能有好多個揹包。這些揹包只要出現一個就行。那方案數就是非空子集,也就是
所以累加的時候乘起來。最後統計答案的時候,對於一個w,所有w的倍數的f都要算進去。
然後輸出即可。
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
const int MOD=1e9+7;
int n,q,mod,v[1000003];
map<int,int> m;
int cnt[2003],id,cnt2;
int d[2003];
int jz2[1000003];
int ans[2003];
int gcd(int a,int b){
if(!b)return a;
return gcd(b,a%b);
}
int f[2003][2003];
signed main(){
n=in;q=in;mod=in;jz2[0]=1;for(int i=1;i<=1000000;i++)jz2[i]=jz2[i-1]*2%MOD;
//for(int i=1;i<=10;i++)cout<<jz2[i]<<" ";cout<<endl;
for(int i=1;i<=n;i++)v[i]=gcd(in,mod);
sort(v+1,v+n+1);
for(int i=1;i<=n;i++){
if(v[i]!=v[i-1])v[++id]=v[i],cnt[id]=1;else cnt[id]++;
}n=id;
// for(int i=1;i<=n;i++)cout<<v[i]<<" "<<cnt[i]<<endl;;cout<<endl;
for(int i=1;i*i<=mod;i++){
if(mod%i==0){
d[++cnt2]=i;
if(i*i!=mod)d[++cnt2]=mod/i;
}
}
sort(d+1,d+cnt2+1);
for(int i=1;i<=cnt2;i++)m[d[i]]=i;
//for(int i=1;i<=cnt2;i++)cout<<d[i]<<" ";cout<<endl;
f[0][cnt2]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=cnt2;j++){
int k=m[gcd(d[j],v[i])];
f[i][j]=(f[i][j]+f[i-1][j])%MOD;
f[i][k]=(f[i][k]+f[i-1][j]*(jz2[cnt[i]]-1)%MOD)%MOD;
}
}
// for(int i=1;i<=n;i++){
// for(int j=1;j<=cnt2;j++)cout<<f[i][j]<<" ";cout<<endl;
// }
for(int i=1;i<=cnt2;i++){
for(int j=1;j<=i;j++){
if(d[i]%d[j]==0)ans[i]=(ans[i]+f[n][j])%MOD;
}
}
// for(int i=1;i<=cnt2;i++)cout<<ans[i]<<" ";cout<<endl;
for(int i=1;i<=q;i++){
cout<<ans[m[gcd(in,mod)]]<<'\n';
}
return 0;
}