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 }
  • 相关阅读:
    使用 requests 维持会话
    使用 requests 发送 POST 请求
    使用 requests 发送 GET 请求
    requests 安装
    使用 urllib 分析 Robots 协议
    使用 urllib 解析 URL 链接
    使用 urllib 处理 HTTP 异常
    使用 urllib 处理 Cookies 信息
    使用 urllib 设置代理服务
    按单生产程序发布
  • 原文地址:https://www.cnblogs.com/Menhera/p/10514800.html
Copyright © 2011-2022 走看看