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),所以现在,我们就得出了$a\cdot 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(i\cdot 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\n",i,prime[i]);
48     }
49     for(int i=1;i<=n;i++)
50     {
51         printf("%d:%d^%d=%d\n",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\n",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 } 

 

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

posted @ 2017-12-05 14:08  JZYshuraK_彧  阅读(342)  评论(0编辑  收藏  举报