BZOJ-1968-[Ahoi2005]COMMON 約數研究
阿新 • • 發佈:2017-10-02
ffffff names 有一種 上線 col pan spl min +=
Description
Input
只有一行一個整數 N(0 < N < 1000000)。Output
只有一行輸出,為整數M,即f(1)到f(N)的累加和。Sample Input
3Sample Output
5題解
這道題剛開始以為是線性篩
但是有一種更優的算法
考慮因子中有因子i的數的數量
1 //考慮有多少個數是以i為因子的 2 #include<bits/stdc++.h> 3 using namespace std; 4 int n,ans; 5 int main(){ 6 scanf("View Code%d",&n); 7 for (int i=1;i<=n;i++) 8 ans+=n/i; 9 printf("%d\n",ans); 10 return 0; 11 }
這個代碼灰常短,也挺好理解的
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 usingView Codenamespace 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\n",ans); 31 return 0; 32 }
BZOJ-1968-[Ahoi2005]COMMON 約數研究