线性筛法

线性筛法

1. 算法分析

关键思想:每个数字都被它的最小质因数筛掉

1.1 线性筛求素数

  1. i   %   p j   =   0 i\ \%\ p_j \ =\ 0 i % pj = 0,说明 p j p_j pj i i i 的最小质因数,因此 i ∗ 质 数 i*质数 i 的最小质因子也是 p j p_j pj,在 i i i 递增的时候也会被筛掉,因此不需要在这里判断,可以break
  2. i   %   p j ≠ 0 i\ \%\ p_j \ne 0 i % pj=0,说明 p j p_j pj i ∗ p j i*p_j ipj 的最小质因数,因此 p j p_j pj 可以筛掉 i ∗ p j i * pj ipj

1.2 线性筛求欧拉函数

  1. i   %   p j   =   0 i\ \%\ p_j \ =\ 0 i % pj = 0,说明 p j p_j pj i i i 的最小质因数, φ ( i ∗ p j ) = i ∗ p j ∗ ∏ i = 1 s p i − 1 p i = p j ∗ ( i ∗ ∏ i = 1 s p i − 1 p i ) = p j ∗ φ ( i ) \varphi(i * p_j) = i * p_j * \prod_{i=1}^{s}\frac{p_i-1}{p_i} = p_j * (i * \prod_{i=1}^{s}\frac{p_i-1}{p_i}) = p_j * \varphi(i) φ(ipj)=ipji=1spipi1=pj(ii=1spipi1)=pjφ(i)
  2. i   %   p j ≠ 0 i\ \%\ p_j \ne 0 i % pj=0, 说明 i i i p j p_j pj 互质, 那么 φ ( i ∗ p j ) = φ ( i ) ∗ φ ( p j ) = φ ( i ) ∗ ( p j − 1 ) \varphi(i*p_j) = \varphi(i) * \varphi(p_j) = \varphi(i) * (p_j - 1) φ(ipj)=φ(i)φ(pj)=φ(i)(pj1)

1.3 线性筛求莫比乌斯函数

莫比乌斯函数 μ ( n ) \mu(n) μ(n)
$\mu(n)= \begin{cases} 1&n=1\ 0&n\text{ 含有平方因子}\ (-1)^k&k\text{ 为 }n\text{ 的本质不同质因子个数}\ \end{cases} $

  1. i   %   p j   =   0 i\ \%\ p_j \ =\ 0 i % pj = 0,说明 p j p_j pj的幂次为2,因此 μ ( i ∗ p j ) = 0 \mu(i*p_j) = 0 μ(ipj)=0
  2. i   %   p j ≠ 0 i\ \%\ p_j \ne 0 i % pj=0, 说明 i i i p j p_j pj 互质, μ ( i ∗ p j ) = μ ( i ) ∗ μ ( p j ) = − μ ( i ) \mu(i * p_j) = \mu(i) * \mu(p_j) = -\mu(i) μ(ipj)=μ(i)μ(pj)=μ(i)

1.4 线性筛求约数个数

d(i) 表示 i 的约数个数,num[i] 表示 i 的最小素因子的个数

  1. i % p j ! = 0 i \% p_j != 0 i%pj!=0, 则 p j p_j pj i ∗ p j i * p_j ipj的最小质因数,且 p j p_j pj这个质因数第一次出现在 i ∗ p j i*p_j ipj内,次数为1,则 n u m [ i ∗ p j ] = 1 , d [ i ∗ p j ] = d [ i ] ∗ 2 num[i * p_j] = 1, d[i * p_j] = d[i] * 2 num[ipj]=1,d[ipj]=d[i]2
  2. i % p j = 0 i \% p_j = 0 i%pj=0, 则 p j p_j pj i ∗ p j i*p_j ipj中的次数加一,对于约数个数,先除以原来的 n u m [ i ] + 1 num[i] + 1 num[i]+1,再乘上新的 n u m [ i ] + 2 num[i] + 2 num[i]+2,则 n u m [ i ∗ p j ] = n u m [ i ] + 1 , d [ i ∗ p j ] = d [ i ] / ( n u m [ i ] + 1 ) ∗ ( n u m [ i ] + 2 ) = d [ i ] / n u m [ i ∗ p j ] ∗ ( n u m [ i ∗ p j ] + 1 ) num[i * p_j] = num[i] + 1, d[i * p_j] = d[i] / (num[i] + 1) * (num[i] + 2) = d[i] / num[i * p_j] * (num[i * p_j] + 1) num[ipj]=num[i]+1,d[ipj]=d[i]/(num[i]+1)(num[i]+2)=d[i]/num[ipj](num[ipj]+1)

1.5 线性筛求约束和

f[i]表示i的约数和,gi表示i的最小质因数的 p 0 + p 1 + . . . + p k p^0+p^1+...+p^k p0+p1+...+pk

  1. i % p j ! = 0 i \% p_j != 0 i%pj!=0, 则 p j p_j pj i ∗ p j i * p_j ipj的最小质因数,且 p j p_j pj这个质因数第一次出现在 i ∗ p j i * p_j ipj内,次数为1,则 f [ i ∗ p j ] = f [ i ] ∗ f [ p j ] , g [ i ∗ p j ] = 1 + p j f[i * p_j] = f[i] * f[p_j], g[i * p_j] = 1 + p_j f[ipj]=f[i]f[pj],g[ipj]=1+pj
  2. i % p j = 0 i \% p_j = 0 i%pj=0, 则 p j p_j pj i ∗ p j i * p_j ipj中的次数加一,则 g [ i ∗ p j ] = g [ i ] ∗ p j + 1 , f [ i ∗ p j ] = f [ i ] / g [ i ] ∗ g [ i ∗ p j ] g[i * p_j] = g[i] * p_j + 1, f[i * p_j] = f[i] / g[i] * g[i * p_j] g[ipj]=g[i]pj+1,f[ipj]=f[i]/g[i]g[ipj]

2. 模板

2.1 线性筛求素数

// 线性筛素数(以下把prime[j]这个数简写为pj)
// 如何保证线性:一个合数只能被筛掉一次
// 如何保证一个数字只被筛掉一次:这个数字只被它的最小质因数筛掉,当它的其他质因数想要筛掉它时,将无法进行筛除操作
void get_prime(int n) {
    for (int i = 2; i <= n; ++i) {
        if (!st[i]) prime[cnt++] = i; // 如果这个数字没有被记录,那么这个数字必然为素数,记录一下
        for (int j = 0; prime[j] <= n/i; ++j) {
            st[prime[j] * i] = true;  // 筛掉pj*i这个合数
            if (i % prime[j] == 0)  break; // i%pj==0,说明pj是i的最小素因子,因此i*素数的最小素因子也是pj,在i递增的时候也会被筛掉,因此不需要在这里判断
        }                
    }
}

2.2 线性筛求欧拉函数

void init(int n) {
    phi[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!st[i]) prime[cnt++] = i, phi[i] = i - 1;  // i是质数,phi[i] = i - 1
        for (int j = 0; prime[j] <= n / i; ++j) {
            st[prime[j] * i] = 1;
            if (i % prime[j] == 0) {
                phi[i * prime[j]] = phi[i] * prime[j];  // i % pj == 0, phi[i * pj] = phi[i] * pj
                break;
            }
            phi[i * prime[j]] = phi[i] * (prime[j] - 1);  // i % pj != 0, phi[i * pj] = phi[i] * (pj - 1)
        }
    }
    return;
}

2.3 线性筛求莫比乌斯函数

// 预处理得到莫比乌斯函数
void init(int n) {
    mu[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!st[i]) prime[cnt++] = i, mu[i] = -1;  // i是质数,mu[i] = -1
        for (int j = 0; prime[j] <= n / i; ++j) {
            st[prime[j] * i] = 1;
            if (i % prime[j] == 0) {
                mu[i * prime[j]] = 0;  // i % pj==0, mu[i*pj] = 0
                break;
            }
            mu[i * prime[j]] = -mu[i];  // i % pj!=0, mu[i * pj] = -mu[i]
        }
    }
    return;
}

2.4 线性筛求约数个数

// d(i) 表示 i 的约数个数,num[i] 表示 i 的最小素因子的个数 
void init(int n) {
    d[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if(!st[i]) prime[cnt++] = i, d[i] = 2, num[i] = 1;  //i是质数,d[i] = 2, num[i] = 1
        for (int j = 0; prime[j] <= n / i; ++j) {
            st[i * prime[j]] = 1;
            if (i % prime[j] == 0) {  // i % pj == 0, num[i * pj] = num[i] + 1, d[i *pj] = d[i] / num[i * pj] * (num[i * pj] + 1)
                num[i * prime[j]] = num[i] + 1;
                d[i * prime[j]] = d[i] / num[i * prime[j]] * (num[i * prime[j]] + 1);
                break;
            }
            // i % pj != 0, num[i * pj] = 1, d[i * pj] = d[i] * 2
            num[i * prime[j]] = 1;
            d[i * prime[j]] = d[i] * 2;
        }
    }
    return;
}

2.5 线性筛求约数和

// f[i] 表示i的约数和,g[i]表示i的最小质因数的p^0 + p^1 + ... + p^k
void init(int n) {
    g[1] = f[1] = 1;
    for (int i = 2; i <= n; ++i) {
        if (!st[i]) prime[cnt++] = i, g[i] = 1 + i, f[i] = i + 1;  // i是质数,g[i] = 1 + i, f[i] = i + 1
        for (int j = 0; prime[j] <= n / i; ++j) {
            st[i * prime[j]] = 1;
            if (i % prime[j] == 0) {  // i % pj == 0, g[i * pj] = g[i] * pj + 1, f[i * pj] = f[i] / g[i] * g[i * pj]
                g[i * prime[j]] = g[i] * prime[j] + 1;
                f[i * prime[j]] = f[i] / g[i] * g[i * prime[j]];
                break;
            }
            // i % pj != 0, f[i * pj] = f[i] * f[pj], g[i * pj] = 1 + pj
            f[i * prime[j]] = f[i] * f[prime[j]];
            g[i * prime[j]] = 1 + prime[j];
        }
    }
    return ;
}
论坛软件系统亦称电子公告板(BBS)系统,它伴随社区BBS的流行而成为互联网最重要的应用之一,也逐渐成为网站核心竞争力的标志性体现。2006年7月 CNNIC 发布的最新统计表明,43.2% 的中国网民经常使用论坛/BBS/讨论组,论坛社区应用首次超过即时通讯 IM ,成为仅次于收发Email的互联网基本应用。 Crossday Discuz! Board(以下简称 Discuz!,中国国家版权局著作权登记号 2006SR11895)是康盛创想(北京)科技有限公司(英文简称Comsenz)推出的一套通用的社区论坛软件系统,用户可以在不需要任何编程的基础上,通过简单的设置和安装,在互联网上搭建起具备完善功能、很强负载能力和可高度定制的论坛服务。Discuz! 的基础架构采用世界上最流行的 web 编程组合 PHP+MySQL 实现,是一个经过完善设计,适用于各种服务器环境的高效论坛系统解决方案。 作为国内最大的社区软件及服务提供商,Comsenz旗下的 Discuz! 开发组具有丰富的 web 应用程序设计经验,尤其在论坛产品及相关领域,经过长期创新性开发,掌握了一整套从算法,数据结构到产品安全性方面的领先技术。使得 Discuz! 无论在稳定性,负载能力,安全保障等方面都居于国内外同类产品领先地位。 自2001年6月面世以来,Discuz!已拥有五年以上的应用历史和三十多万网站用户案例,是全球成熟度最高、覆盖率最大的论坛软件系统之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值