zoukankan      html  css  js  c++  java
  • bzoj 2154 Crash的数字表格(莫比乌斯反演及优化)

    Description

    今天的数学课上,Crash小朋友学习了最小公倍数(Least Common Multiple)。对于两个正整数a和b,LCM(a, b)表示能同时被a和b整除的最小正整数。例如,LCM(6, 8) = 24。回到家后,Crash还在想着课上学的东西,为了研究最小公倍数,他画了一张N*M的表格。每个格子里写了一个数字,其中第i行第j列的那个格子里写着数为LCM(i, j)。一个4*5的表格如下: 1 2 3 4 5 2 2 6 4 10 3 6 3 12 15 4 4 12 4 20 看着这个表格,Crash想到了很多可以思考的问题。不过他最想解决的问题却是一个十分简单的问题:这个表格中所有数的和是多少。当N和M很大时,Crash就束手无策了,因此他找到了聪明的你用程序帮他解决这个问题。由于最终结果可能会很大,Crash只想知道表格里所有数的和mod 20101009的值。

    Input

    输入的第一行包含两个正整数,分别表示N和M。

    Output

    输出一个正整数,表示表格中所有数的和mod 20101009的值。

    Sample Input

    4 5

    Sample Output

    122
    【数据规模和约定】
    100%的数据满足N, M ≤ 107。
     
    【思路】
     
      这个博客推倒过程挺详细的 click here
      我是图片的搬运工
      
      
      到此为止,只要两个循环都用个分块就可以解决2154了。
     
    【代码】
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 using namespace std;
     5 
     6 typedef long long ll;
     7 const int N = 1e7+10;
     8 const int MOD = 20101009;
     9 
    10 ll mu[N],su[N],sz,np[N];
    11 int n,m,mx;
    12 
    13 void get_mu()
    14 {
    15     int i,j;
    16     mu[1]=1;
    17     for(i=2;i<=mx;i++) {
    18         if(!np[i])
    19             su[++sz]=i,mu[i]=-1;
    20         for(j=1;j<=sz&&i*su[j]<=mx;j++) {
    21             np[i*su[j]]=1;
    22             if(i%su[j]==0)
    23                 mu[i*su[j]]=0;
    24             else
    25                 mu[i*su[j]]=-mu[i];
    26         }
    27     }
    28     for(i=1;i<=mx;i++)
    29         mu[i]=(mu[i-1]+(ll)(mu[i]*i*i)%MOD)%MOD;
    30 }
    31 ll t(ll x,ll y)
    32 {
    33     return ((ll)(x*(x+1)/2%MOD)*(ll)(y*(y+1)/2%MOD)%MOD);
    34 }
    35 ll F(int n,int m)
    36 {
    37     int i,last; ll ans=0;
    38     for(i=1;i<=n;i=last+1) {
    39         last=min(n/(n/i),m/(m/i));
    40         ans=(ans+(ll)(mu[last]-mu[i-1])*t(n/i,m/i)%MOD)%MOD;
    41     }
    42     return ans;
    43 }
    44 int main()
    45 {
    46     //freopen("in.in","r",stdin);
    47     //freopen("out.out","w",stdout);
    48     scanf("%d%d",&n,&m);
    49     if(n>m) swap(n,m);
    50     mx=n;
    51     get_mu();
    52     int last; ll ans=0;
    53     for(int i=1;i<=n;i=last+1) {
    54         last=min(n/(n/i),m/(m/i));
    55         ans=(ans+((ll)(i+last)*(last-i+1)/2*F(n/i,m/i)%MOD))%MOD;
    56     }
    57     printf("%lld",(ans+MOD)%MOD);
    58     return 0;
    59 }

    【优化】

      我是图片的搬运工

      

      (H打错为F 233)

      积性函数的约数和也是积性函数,H(D) 可以用线性筛求,然后求下前缀和就好了。

      至此为止,可以解决2693的多查询问题了。

     
    【代码】
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 using namespace std;
     5 
     6 typedef long long ll;
     7 const int N = 1e7+10;
     8 const int MOD = 20101009;
     9 
    10 ll sum[N],su[N],sz,np[N];
    11 int n,m,mx;
    12 
    13 void get_mu()
    14 {
    15     int i,j;
    16     sum[1]=1;
    17     for(i=2;i<=mx;i++) {
    18         if(!np[i]) {
    19             su[++sz]=i,
    20             sum[i]=(i-(ll)i*i)%MOD;
    21         }
    22         for(j=1;j<=sz&&i*su[j]<=mx;j++) {
    23             np[i*su[j]]=1;
    24             if(i%su[j]==0)
    25                 sum[i*su[j]]=(su[j]*sum[i])%MOD;
    26             else
    27                 sum[su[j]*i]=(sum[su[j]]*sum[i])%MOD;
    28         }
    29     }
    30     for(i=1;i<=mx;i++)
    31         sum[i]=(sum[i]+sum[i-1])%MOD;
    32 }
    33 ll S(ll x,ll y)
    34 {
    35     return ((ll)(x*(x+1)/2%MOD)*(ll)(y*(y+1)/2%MOD)%MOD);
    36 }
    37 
    38 int main()
    39 {
    40     //freopen("in.in","r",stdin);
    41     //freopen("out.out","w",stdout);
    42     mx=1e7;
    43     get_mu();
    44     int T; scanf("%d",&T);
    45     while(T--) {
    46         scanf("%d%d",&n,&m);
    47         if(n>m) swap(n,m);
    48         mx=n; get_mu();
    49         int last; ll ans=0;
    50         for(int i=1;i<=n;i=last+1) {
    51             last=min(n/(n/i),m/(m/i));
    52             ans=(ans+(ll)S(n/i,m/i)*(sum[last]-sum[i-1])%MOD)%MOD;
    53         }
    54         printf("%lld
    ",(ans+MOD)%MOD);
    55     }
    56     return 0;
    57 }
      两倍经验get :)
      最后扔上popoqqq神犇的ppt click here
     
  • 相关阅读:
    Linux命令应用大词典-第11章 Shell编程
    Kubernetes 学习12 kubernetes 存储卷
    linux dd命令
    Kubernetes 学习11 kubernetes ingress及ingress controller
    Kubernetes 学习10 Service资源
    Kubernetes 学习9 Pod控制器
    Kubernetes 学习8 Pod控制器
    Kubernetes 学习7 Pod控制器应用进阶2
    Kubernetes 学习6 Pod控制器应用进阶
    Kubernetes 学习5 kubernetes资源清单定义入门
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5251081.html
Copyright © 2011-2022 走看看