笔记汇总
代码
void init(int n)
{
// 质数从 2 开始出现
for (int i = 2; i <= n; i ++ )
{
if (!v[i]) p[ ++ m] = i; // 没有被更小的质因子标记过,所以为质数
for (int j = 1; p[j] * i <= n; j ++ ) // 通过质因子标记合数,不能大于上界 n
{
v[i * p[j]] = true; // 标记为合数
if (i % p[j] == 0) break;
// 此时 p[j] 为 i 的一个质因子,也就是存在一个 t,满足 p[j] * t == i
// 因为要求每个合数仅被它的最小素因子筛去正好一次,i 的质因数若小于 p[j],
// 就不满足为最小质因数,所以直接退出
}
}
}
优化
因为一个数 n 的最小质因数不超过 √n,
所以我们只需要预处理 0 到 √n 范围内的质数,
就可以在 O((r−l)logn) 的时间内找出 l 到 r 之间的所有质数(l<=r<=n)
阶乘分解
因为 N! 中的质因数,等于 [1,n] 中每个数的质因数的总和,
对于某质因数 p,其倍数都包含这个质因数,则共有 [np] 个,
由此可知 有两个质因子 p 的数,个数为 [np2],用线性筛筛出质数后,累计即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, m;
int p[N], v[N];
inline bool check(int a, int b)
{
return a / b * b == a;
}
void init(int n)
{
for (int i = 2; i <= n; i ++ )
{
if (!v[i]) p[ ++ m] = i;
for (int j = 1; p[j] * i <= n; j ++ )
{
v[p[j] * i] = 1;
if (check(i, p[j])) break;
}
}
}
int main()
{
scanf("%d", &n);
init(n);
for (int i = 1; i <= m; i ++ )
{
int s = 0;
for (int j = n; j; j /= p[i]) s += j / p[i];
printf("%d %d\n", p[i], s);
}
return 0;
}