线性筛

数论函数

\(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)\)

\[f(a)(b) \\=\sum_{u|a}u\sum_{v|b}v \\=\sum_{u|a}\sum_{v|b}uv \]

因为\(a⊥b\),所以\(u⊥v\)

所以\(ab\)的因数一定是选 \(一个a的因数\times一个b的因数\)

所以上式可写为

\[=\sum_{(uv)|(ab)}uv \\=\sum_{d|x}d \]

利用积性函数的性质

枚举\(i\)进行讨论:

  1. 质数的情况

  2. \(i⊥p_j\)的情况

  3. \(p_j\)\(i\)最小质因子的情况

\(1\)\(n\)的约数个数函数\(\sigma^0\)

显然\(\sigma^0\)\(\sigma\)一样都是积性函数。

\[n=\prod_{i=1}^k{p_i}^{c_i} (p_i是质数) \]

通过小学奥数我们知道

\[\sigma(n)=\prod_{i=1}^k(c_i+1) \]

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]\)

\[n=\prod_{i=1}^k{p_i}^{c_i} (p_i是质数) \]

通过容斥原理可得

\[\varphi(n) \\=\prod_{i=1}^k(p_i-1)p_i^{c_i-1} \\=n\prod_{i=1}^k(1-\frac{1}{p_i}) \\ \]

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的莫比乌斯函数\(μ\)

\[n=\prod_{i=1}^k{p_i}^{c_i} (p_i是质数) \]

\(\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):\)

  1. 如果\(\mu(a) = 0\)\(\mu(b)=0\)。则\(ab\)必含平方因子
  2. 否则,由于\(a⊥b\)。所以\(ab\)不含平方因子,所

\[\mu(a)\mu(b)=(-1)^{k_a}(-1)^{k_b}=(-1)^{k_a+k_b}=\mu(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})\)的关系式。

posted @ 2020-04-20 12:52  Oply  阅读(239)  评论(1编辑  收藏  举报