zoukankan      html  css  js  c++  java
  • 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
    ",chs[x]);
    75     }
    76 }
    77 
    78 int main(){
    79     read();
    80     work();
    81     return 0;
    82 }
  • 相关阅读:
    C#不显示在任务栏
    打开文件,文件夹
    C#文本操作
    C#路径2
    C#当前程序路径获取
    HDU 5155 Harry And Magic Box dp
    POJ 1971 Parallelogram Counting
    CodeForces 479C Exams 贪心
    CodeForces 508E Arthur and Brackets 贪心
    CodeForces 483B 二分答案
  • 原文地址:https://www.cnblogs.com/Menhera/p/10514800.html
Copyright © 2011-2022 走看看