[BZOJ 1968] [AHOI 2005] 约数研究

Description

img

Input

只有一行一个整数 \(N\)

Output

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

Sample Input

3

Sample Output

5

HINT

\(0 < N < 1000000\)

Solution

〖线性筛约数个数〗

\(d[i]\) 表示 \(i\) 的约数个数,\(num[i]\) 表示 \(i\) 的最小质因子的出现次数。

\(i=p_1^{k_1}p_2^{k_2}\cdots p_n^{k_n}\),有 \(d[i]=(k_1+1)(k_2+1)\cdots(k_n+1)\)

  • \(i\) 是质数,则 \(d[i]=2,num[i]=1\)
  • \(i \bmod p[j] \ne 0\),即 \(i\) 不包含质因子 \(p[j]\),那么 \(d[i\times p[j]]=(k_1+1)(k_2+1)\cdots(k_n+1)(1+1)=d[2]\times 2\),又因为是从小到大枚举,所以 \(p[j]\) 一定是 \(i\times p[j]\) 的最小质因子,那么 \(num[i\times p[j]]=1\)
  • \(i \bmod p[j]=0\),则 \(p[j]\) 一定是 \(i\) 的最小质因子,那么 \(d[i\times p[j]]=(k_1+1+1)(k_2+1)\cdots(k_n+1)=d[i]/(num[i]+1)\times(num[i]+2),\)\(num[i\times p[j]]=num[i]+1\)
void euler() {
    for (int i = 2; i <= n; ++i) {
        if (!np[i]) p[++tot] = i, d[i] = 2, num[i] = 1;
        for (int j = 1; j <= tot && i * p[j] <= n; ++j) {
            np[i * p[j]] = 1;
            if (i % p[j] == 0) {
                d[i * p[j]] = d[i] / (num[i] + 1) * (num[i] + 2);
                num[i * p[j]] = num[i] + 1; break;
            }
            d[i * p[j]] = d[i] * 2, num[i * p[j]] = 1;
        }
    }
}

〖线性筛约数和〗

\(sd[i]\) 表示 \(i\) 的所有约数之和,则 \(sd[i]=(1+p_1+p_1^2+\cdots+p_1^{k_1})(1+p_2+p_2^2+\cdots+p_2^{k_2})\cdots(1+p_n+p_n^2+\cdots+p_n^{k_n})\)

\(m\)\(i\) 的最小质因子 \(p\) 出现的次数,设 \(sp[i]=1+p+p^2+\cdots+p^m\)

  • \(i\) 是质数,则 \(sd[i]=sq[i]=i+1\)
  • \(i\bmod p[j]\ne 0\),则 \(sd[i\times p[j]]=(1+p_1+p_1^2+\cdots+p_1^{k_1})(1+p_2+p_2^2+\cdots+p_2^{k_2})\)\(\cdots(1+p_n+p_n^2+\cdots+p_n^{k_n})(1+p[j])\)\(~=sd[i]\times (p[j] + 1)\),而 \(p[j]\) 又是 \(i\times p[j]\) 的出现次数最小的质因子,所以 \(sp[i\times p[j]]=p[j]+1\)
  • \(i\bmod p[j]=0\),则 \(p[j]\) 一定是 \(i\) 的出现次数最小的质因子,则 \(sd[i\times p[j]]=(1+p_1+p_1^2+\cdots+p_1^{k_1}+p_1^{k_1+1})(1+p_2+p_2^2+\cdots+p_2^{k_2})\)\(\cdots(1+p_n+p_n^2+\cdots+p_n^{k_n})\)\(~=sd[i]/sp[i]\times (sp[i]\times p[j]+1),sp[i\times p[j]]=sp[i]\times p[j]+1\)
void euler() {
    for (int i = 2; i <= n; ++i) {
        if (!np[i]) p[++tot] = i, sd[i] = sp[i] = i + 1;
        for (int j = 1; j <= tot && i * p[j] <= n; ++j) {
            np[i * p[j]] = 1;
            if (i % p[j] == 0) {
                sp[i * p[j]] = sp[i] * (sp[i] * p[j] + 1);
                sd[i * p[j]] = sd[i] / sp[i] * sp[i * p[j]]; break;
            }
            sd[i * p[j]] = sd[i] * (p[j] + 1), sp[i * p[j]] = p[j] + 1;
        }
    }
}

Code

猜你喜欢

转载自www.cnblogs.com/fly-in-milkyway/p/10371981.html
今日推荐