线性筛
数论函数
\(f(n)\),定义域为\(N\)(正整数域),值域为\(N\)的函数。
常见:
\(f(x) = x\)
\(f(x)=x^2\)
\(f(x)=\sum_{i=1}^xi=\frac{x(x+1)}{2}\)
\(f(x)=\sum_{i=0}^x2^i=2^{x+1}-1\)
\(f(x)=\sum_{d|x}d\)
积性函数
\(f(x)\),如果\(\forall a,b,a⊥b,ab=x,f(a)(b)=f(x)\),则称\(f\)为积性函数。
比如:
\(f(x)=x\)
\(f(x)=x^2\)
\(φ(x)\) — 欧拉函数
\(\mu(x)\) — 莫比乌斯函数
\(gcd(x,k)\) — \(k\)固定时的最大公因数
\(σ(x)\) — \(x\)的因数之和
\(σ^0(x)\) — \(x\)的因数个数
线性筛
找出\(1\)—\(n\)内的所有质数
Etratosthenes筛
开始认为所有数都是质数。暴力枚举每个数,如果是质数,就将它所有的倍数标为非质数。
bool is[N]; // 标记数组
int p[N], cn; // 质数数组
memset(is, 1, sizeof(is));
is[1] = 0;
for (int i = 2; i <= n; i++)
if (is[i])
{
p[++cn] = i;
for (int j = i * i; j <= n; j += i)
is[j] = 0;
}
时间复杂度\(O(n log^2_n)\),懒得写线性筛就写这玩意
线性筛
让每个数被其最小质因子筛掉,这样就可以实现每个数只被筛一次。
bool is[N]; // 标记数组
int p[N], cn; // 质数数组
memset(is, 1, sizeof(is));
is[0] = is[1] = 0;
for (int i = 2; i <= n; i++)
{
if (is[i]) p[++cn] = i;
for (int j = 1; j <= cn && i * p[j] <= n; j++)
{
is[i * p[j]] = 0;
if (i % p[j] == 0) break; // i已经包含p[j],继续枚举p[j]一定大于当前,不会是i*p[j]的最小质因子
}
}
求\(1\)—\(n\)的约数和函数\(\sigma\)
\(\sigma (n)\)
证明:
考虑\(a,b(a⊥b,ab=x)\)
因为\(a⊥b\),所以\(u⊥v\)。
所以\(ab\)的因数一定是选 \(一个a的因数\times一个b的因数\)
所以上式可写为
利用积性函数的性质
枚举\(i\)进行讨论:
-
质数的情况
-
\(i⊥p_j\)的情况
-
\(p_j\)是\(i\)最小质因子的情况
求\(1\)—\(n\)的约数个数函数\(\sigma^0\)
显然\(\sigma^0\)和\(\sigma\)一样都是积性函数。
设
通过小学奥数我们知道
bool is[N]; // 标记数组
int p[N], cn, g[N], f[N]; // g[x]表示x的最小质因子的次数
memset(is, 1, sizeof(is));
is[0] = is[1] = 0;
for (int i = 2; i <= n; i++)
{
if (is[i]) p[++cn] = i, g[i] = 1, f[i] = 1;
for (int j = 1; j <= cn && i * p[j] <= n; j++)
{
int x = i * p[j];
//p[j]为x的最小质因子
is[x] = 0;
if (i % p[j] == 0)
{
g[x] = g[i] + 1;
f[x] = f[i] * (g[x] + 1) / (g[i] + 1);
break;
}
else
g[x] = 1,
f[x] = f[i] * 2;
// i不是p[j]的倍数,互质
}
}
求1—n的欧拉函数\(\varphi\)
\(\varphi(n) = \sum_{i=1}^n[i⊥n]\)
设
通过容斥原理可得
bool is[N]; // 标记数组
int p[N], cn, f[N];
memset(is, 1, sizeof(is));
is[0] = is[1] = 0;
for (int i = 2; i <= n; i++)
{
if (is[i]) p[++cn] = i, f[i] = i - 1; // 质数时f[i]=i-1
for (int j = 1; j <= cn && i * p[j] <= n; j++)
{
int x = i * p[j];
//p[j]为x的最小质因子
is[x] = 0;
if (i % p[j] == 0)
{
f[x] = f[i] * p[j];
break;
}
f[x] = f[i] * f[p[j]];
// i不是p[j]的倍数,互质
}
}
求1—n的莫比乌斯函数\(μ\)
设
\(\mu(n)=\begin{cases} 1& n=1 \\ (-1)^k & n无平方数因数 \\ 0 & otherwise \end{cases}\)
\(\mu\)是积性函数证明:
\(\forall a,b,a⊥b,ab=x\)
\(\mu(a)(b):\)
- 如果\(\mu(a) = 0\)或\(\mu(b)=0\)。则\(ab\)必含平方因子
- 否则,由于\(a⊥b\)。所以\(ab\)不含平方因子,所
bool is[N]; // 标记数组
int p[N], cn, f[N]; // 质数数组
memset(is, 1, sizeof(is));
is[0] = is[1] = 0;
for (int i = 2; i <= n; i++)
{
if (is[i]) p[++cn] = i, f[i] = -1; // 质数肯定标为-1
for (int j = 1; j <= cn && i * p[j] <= n; j++)
{
int x = i * p[j];
is[x] = 0;
if (i % p[j] == 0)
{
f[x] = 0; break; // x为(p[j]^2)的倍数,有平方因子
}
f[x] = -f[i]; // p[j]是质数,f[p[j]]=-1
}
}
一般积性函数
一个积性函数\(f\),可以考虑以下的线性筛法:
要计算\(f(n)\),考虑到\(n=\prod_{i=1}^k{p_i}^{c_i} (p_i是质数)\)
在线性筛的过程中,如果\(i \mod p_j \ne0\),就有\(f(ip_j)=f(i)f(p_j)\)
否则,考虑\(k|(ip_j),k⊥p_j\),则有\(f(ip_j)=f(k)f(\frac{ip_j}k)\)
因此,我们只需要记录对于每一个\(ip_j\)对应的\(k\),或者推导出\(f(p^c)\)到\(f(p^{c+1})\)的关系式。