洛谷題單指南-數學基礎問題-P1403 [AHOI2005] 約數研究

江城伍月發表於2024-04-16

原題連結:https://www.luogu.com.cn/problem/P1403

題意解讀:計算1~n每個數的約數個數之和。

解題思路:

1、數學方法

1~n的約數範圍也在1~n,要計算每個數的約數個數之和

可以從約數出發,

比如約數是x,那麼在1~n中一共有n/x個數包含x這個約數

x從1一直列舉到n,就可以得出每個約數是多少個數的約數

求和即可

100分程式碼:

#include <bits/stdc++.h>
using namespace std;

int n;
long long ans;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) ans += n / i;
    cout << ans;
    return 0;
}

2、埃氏篩法

數學的方法不太好想!

我們知道:

對於一個數x,分解質因數為x=p1a1*p2a2*...*pnan,則x的約數個數f(x) = (1+a1)*(1+a2)*...*(1+an)

可以用組合數來解釋,每個質因數的指數可以取0~ai,也就是1+ai種,乘法原理就可以得到約數的個數。

而埃氏篩法,會用每一個素數去篩包含其為素因子的合數,

這樣就可以在埃氏篩的過程中,當用素數i乘以倍數之後得j,在標記j為合數的的同時

也可以計算j一共包含多少個i因子(設為cnt個),然後在f[j]上乘以(1+cnt),就得到素因子i對f[j]的貢獻

最後把f[1]~f[n]加起來即可

100分程式碼:

#include <bits/stdc++.h>
using namespace std;

const int N = 1e6 + 5;
int n;
int f[N], g[N];
bool flag[N];
long long ans;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++) g[i] = i, f[i] = 1; 
    for(int i = 2; i <= n; i++)
    {
        if(!flag[i])
        {
            f[i] = 2; //素數的約數個數是2
            for(int j = i + i; j <= n; j += i)
            {
                flag[j] = true;
                int cnt = 0;
                while(g[j] % i == 0) cnt++, g[j] /= i; //統計g[j]有多少個i素因子
                f[j] = f[j] * (1 + cnt);
            }
        }
    }
    for(int i = 1; i <= n; i++) ans += f[i];
    cout << ans;
    return 0;
}

相關文章