zoukankan      html  css  js  c++  java
  • Divisor counting [线性筛积性函数]

    Divisor counting  

        题目大意:定义f(n)表示整数n的约数个数。给出正整数n,求f(1)+f(2)+...+f(n)的值。

        注释:1<=n<=1000,000

          想法:我们再次有两种做法:文...武.....。想讲武的......我们其实这次更博只是为了介绍一种知识点——线性筛法筛积性函数。这里,给出线性筛的万能筛法。

          1.初值:显然,初值是必要的。

          2.我们类比欧拉筛,用k(n)举例。当n是素数时的情况使我们必须的,这相当于初值一样重要。

          3.又因为,我们主要筛积性函数,显然函数是否为积性。如果gcd(a,b)=1,我们需要知道k(a*b)是否等于k(a)*f(b)。

          4.紧接着,我们需要知道如果n是整数的幂次,有什么用呢?在5中我们会用到。

          5.最后的,我们需要明白对于任意的a来讲,如果这个a被prime[j]筛到了,我们思考如何才能将k(a)用我们已知的值筛出。我们讨论:

            1)如果gcd(prime[i],a)=prime[j],我们设想:我们可以记录a的最小质因子以及这个最小质因子的个数,显然:a的最小质因子一定是prime[j]。为什么?因为线性筛保证每一个数是会被它的最小质因子筛掉。prime[j]*a的最小质因子如果不是prime[j],那它为什么会被prime[j]筛到?不会啊!它只会被最小者筛掉,所以我们此时保证了a的最小质因子一定不小于prime[j]。又因为此时我们发现:prime[j] | a 所以,我们知道,a的最小质因子一定是prime[j]。我们又记录了a中最小质因子的幂次h(a),所以现在,我们就得出了$acdot prime[j]=frac{a}{pirme[j]^{h(a)}}cdot {prime[j]^{h(a)+1}}$。这时,我们用到了第3条,$frac{a}{prime[j]^{h(i)}}$和$prime[j]^{h(i)+1}$显然是互质的!$frac{a}{prime[j]^{h(i)}}$的值我们显然已经求过,$prime[j]^{h(i)+1}$的值呢?第4条在这里!所以这种情况就证好了。

            2)如果gcd(prime[i],a)!=prime[j],那么我们想,它会等于什么?我们已经证明了g(i)是一定不小于prime[j],此时,g(i)!=prime[j]。所以,显然的,我们有g(i)>prime[j]。但是!此时我们有知道g(i)是i的最小质因子....质因子!!!由于此函数是积性函数,所以,$f(icdot prime[j])=f(i)cdot f(prime[j])$。这...用第2点,证毕。

          文的做法我们会带数论の一波流里提到(数论の一波流的[二]?猛戳),在此不讲......

        最后,附上丑陋的代码......

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 typedef long long ll;
     5 using namespace std;
     6 int prime[1001000];
     7 int h[1000100];//h(i)表示i的最小质因子的个数,即g(i)^h(i)|i但g(i)^(h(i)+1)不行。
     8 int g[1000100];//g(i)表示i的最小质因子
     9 int gh[1000100];
    10 bool v[1000100]={false};
    11 int sigema[1000100];
    12 int cnt=0;
    13 int quick_power(int a,int b)
    14 {
    15     int ans=1;
    16     while(b)
    17     {
    18         if(b&1) ans=(ans*a);
    19         b>>=1;
    20         a=(a*a);
    21     }
    22     return ans;
    23 }
    24 int main()
    25 {
    26     cnt=0;
    27     int n;
    28     scanf("%d",&n);
    29     for(int i=2;i<=n;i++)//我们先快筛g和h,其余的再说.
    30     {
    31         if(!v[i]) prime[++cnt]=i,g[i]=i,h[i]=1,gh[i]=i;
    32         for(int j=1;i*prime[j]<=n&&j<=cnt;j++)
    33         {
    34             v[i*prime[j]]=1;
    35             g[i*prime[j]]=prime[j];
    36             if(g[i]==prime[j])
    37             {
    38                 h[i*prime[j]]=h[i]+1;
    39                 gh[i*prime[j]]=quick_power(g[i*prime[j]],h[i*prime[j]]);
    40                 break;
    41             }
    42             else h[i*prime[j]]=1,gh[i*prime[j]]=prime[j];
    43         }
    44     }
    45     /*for(int i=1;i<=cnt;i++)
    46     {
    47         printf("Prime%d:%d
    ",i,prime[i]);
    48     }
    49     for(int i=1;i<=n;i++)
    50     {
    51         printf("%d:%d^%d=%d
    ",i,g[i],h[i],gh[i]);
    52     }*/
    53     memset(v,0,sizeof(v));
    54     cnt=0;
    55     sigema[1]=1;
    56     for(int i=2;i<=n;i++)
    57     {
    58         if(!v[i]) cnt++,sigema[i]=2;
    59         for(int j=1;i*prime[j]<=n&&j<=cnt;j++)
    60         {
    61             v[i*prime[j]]=1;
    62             if(g[i]==prime[j]){sigema[i*prime[j]]=sigema[i/gh[i]]*(h[i]+2);break;}
    63             else sigema[i*prime[j]]=sigema[i]*2;
    64         }
    65     }
    66     /*for(int i=1;i<=n;i++)
    67     {
    68         printf("Sigema[%d]=%d
    ",i,sigema[i]);
    69     }*/
    70     ll ans=0;
    71     for(int i=1;i<=n;i++)
    72     {
    73         ans+=sigema[i];
    74     }
    75     printf("%lld",ans);
    76     return 0;
    77 } 

        小结:错误,太多了....看看吧......

  • 相关阅读:
    LeetCode 2 -- Add Two Numbers
    LeetCode 1 -- Two Sum
    LeetCode189——Rotate Array
    Win10下IIS配置 C#项目的部署与发布
    Linux查看进程和删除进程
    使用 Visual Studio 将 ASP.NET Core 应用发布到 Linux 上的应用服务
    Spring Boot 设置启动时路径和端口号
    Linux平台部署.net Core SDK
    C#教程之如何在centos操作系统上发布.net core的项目
    Linux如何查看和控制进程
  • 原文地址:https://www.cnblogs.com/ShuraK/p/7986650.html
Copyright © 2011-2022 走看看