Luogu4495 [HAOI2018] 奇怪的背包 【扩展欧几里得算法】
题目分析:
首先打个暴力求一下$10^9$以内因子最多的数的因子个数,发现只有$1344$个。
由于有$ax+by=k*(a,b)$和2017年noip的结论,所以我们可以发现对于任意多个数$a_1,a_2,a_3,...,a_n$他们能组成的数是$k$倍的最大公约数,$k$任取。我们发现如果$gcd%p$不是$w$的因子那么不行,否则可行。所以把$a$数组全部模$p$,再归类为每个因子,再处理相互之间能构建出来的$gcd$,再用莫比乌斯函数做一下容斥,再处理出每个因子的因子和,再对每个输入的$w$模$p$,答案可以$O(1)$回答。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1050000; 5 const int MXF = 1350; 6 const int mod = 1e9+7; 7 8 int n,q,p; 9 int fac[MXF],dt[MXF],num; 10 int a[maxn],chs[MXF],mu[MXF]; 11 int pw2[maxn]; 12 13 int gcd(int a,int b){ 14 if(!b) return a; 15 else return gcd(b,a%b); 16 } 17 18 void divide(){ 19 for(int i=1;i*i<=p;i++){ 20 if(p%i) continue; 21 if(i*i == p) fac[++num] = i; 22 else{ 23 fac[++num] = i; 24 fac[++num] = p/i; 25 } 26 } 27 sort(fac+1,fac+num+1); 28 } 29 30 void read(){ 31 scanf("%d%d%d",&n,&q,&p); 32 divide(); 33 for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i] = gcd(a[i],p); 34 for(int i=1;i<=n;i++){ 35 int z = lower_bound(fac+1,fac+num+1,a[i])-fac; 36 dt[z]++; 37 } 38 for(int i=1;i<=num;i++){ 39 int hh = fac[i]; mu[i] = 1; 40 for(int j=2;j*j<=hh;j++){ 41 int cnt = 0; 42 while(hh % j == 0) cnt++,hh/=j; 43 if(cnt > 1)mu[i] = 0; 44 else if(cnt) mu[i] = 1ll*mu[i]*(mod-1)%mod; 45 } 46 if(hh != 1){mu[i] = 1ll*mu[i]*(mod-1)%mod;} 47 } 48 } 49 50 void work(){ 51 pw2[0] = 1; for(int i=1;i<=n;i++) pw2[i] = pw2[i-1]*2%mod; 52 for(int i=1;i<=num;i++){ 53 int z = 0; 54 for(int j=i;j<=num;j++){ 55 if(fac[j] % fac[i] == 0) z+=dt[j]; 56 } 57 chs[i] = (pw2[z]-1)%mod; 58 } 59 for(int i=1;i<=num;i++){ 60 for(int j=i+1;j<=num;j++){ 61 if(fac[j] % fac[i]) continue; 62 int ct = lower_bound(fac+1,fac+num+1,fac[j]/fac[i])-fac; 63 chs[i] = chs[i]+1ll*mu[ct]*chs[j]%mod; chs[i] %= mod; 64 } 65 } 66 for(int i=num;i>=1;i--){ 67 for(int j=1;j<i;j++){ 68 if(fac[i] % fac[j] == 0) chs[i] += chs[j],chs[i] %= mod; 69 } 70 } 71 for(int i=1;i<=q;i++){ 72 int x; scanf("%d",&x); x = gcd(x,p); 73 x = lower_bound(fac+1,fac+num+1,x)-fac; 74 printf("%d\n",chs[x]); 75 } 76 } 77 78 int main(){ 79 read(); 80 work(); 81 return 0; 82 }