BZOJ-1968-[Ahoi2005]COMMON 约数研究

Description

Input

只有一行一个整数 N(0 < N < 1000000)。

Output

只有一行输出,为整数M,即f(1)到f(N)的累加和。

Sample Input

3

Sample Output

5
 

题解

这道题刚开始以为是线性筛

但是有一种更优的算法

考虑因子中有因子i的数的数量

 1 //考虑有多少个数是以i为因子的
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 int n,ans;
 5 int main(){
 6     scanf("%d",&n);
 7     for (int i=1;i<=n;i++)
 8         ans+=n/i;
 9     printf("%d
",ans);
10     return 0;
11 }
View Code

这个代码灰常短,也挺好理解的

Solution2:

但是如果想不到怎么办

那就只好强上线性筛了

这里先说一下

num[i]表示i的因子个数,Min[i]表示i的最小质因子的次数

我们可以通过约数个数定理来求一个数的因子个数

传送门:https://baike.so.com/doc/5806281-6019081.html

不难发现一个质数的因子个数为2(1和它本身),最小质因子的次数为1

我们在筛质数的时候判断一下prime[j]是否为i的最小质因子

如果是

num[i*prime[j]]等于num[i]/(Min[i]+1)*(Min[i]+2)

Min[i*prime[j]]等于Min[i]+1   //最小质因子次数+1

如果不是

num[i*prime[j]]就等于num[i]*num[prime[j]] //符合积性函数

Min[i*prime[j]]等于1   //i*prime[j]的最小质因子为prime[j]且只有1次

 1 //线性筛
 2 #include<bits/stdc++.h>
 3 #define N 1000005
 4 using namespace std;
 5 int n,ans,cnt;
 6 int prime[N],num[N],Min[N];
 7 bool flag[N];
 8 int main(){
 9     scanf("%d",&n);
10     num[1]=1;
11     for (int i=2;i<=n;i++){
12         if (!flag[i]){
13             prime[++cnt]=i;
14             num[i]=2;
15             Min[i]=1;
16         }
17         for (int j=1;j<=cnt&&i*prime[j]<=n;j++){
18             flag[i*prime[j]]=true;
19             if (!(i%prime[j])){
20                 num[i*prime[j]]=num[i]/(Min[i]+1)*(Min[i]+2);
21                 Min[i*prime[j]]=Min[i]+1;
22                 break;
23             }
24             num[i*prime[j]]=num[i]*num[prime[j]];
25             Min[i*prime[j]]=1;
26         }
27     }
28     for (int i=1;i<=n;i++)
29         ans+=num[i];
30     printf("%d
",ans);
31     return 0;
32 } 
View Code
原文地址:https://www.cnblogs.com/zhuchenrui/p/7619909.html