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 }
小结:错误,太多了....看看吧......