线性筛

数论函数

(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}usum_{v|b}v \=sum_{u|a}sum_{v|b}uv ]

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

所以(ab)的因数一定是选 (一个a的因数 imes一个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} \=nprod_{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)=egin{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 e0),就有(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}))的关系式。

原文地址:https://www.cnblogs.com/oply/p/12737089.html