线性筛

原创 2015年07月08日 16:48:05

今天在看了各种以及听了各种之后终于算是了解线性筛了…
虽然都是一些很基本的应用但还是觉得各种强大…

线性筛素数

代码

int tot_prime, prime[maxn];
bool vist[maxn];
void get_prime(){

    for(int i = 2; i <= n; ++i){
        if(!vist[i]) prime[++tot_prime] = i;
        for(int j = 1; i * prime[j] <= n && j <= tot_prime; ++j){
            vist[i*prime[j]] = true;
            if(i % prime[j] == 0) break;
        }
    }
}

  

一些解释

第一次看到的时候就有一句话觉得很鬼畜…

if(i % prime[j] == 0) break;

果然这段代码最鬼畜的就是这句,今天在翻其他东西的时候偶然发现了这个:

这行代码神奇地保证了每个合数只会被它的最小素因子筛掉,就把复杂度降到了O(N)
接下来是证明这个算法正确性的说明:

prime[]数组中的素数是递增的,当i能整除prime[j],那么iprime[j+1]这个合数肯定被prime[j]乘以某个数筛掉。
因为i中含有prime[j]prime[j]prime[j+1]小,即i=kprime[j],那么iprime[j+1]=(kprime[j])prime[j+1]=kprime[j],接下去的素数同理。所以不用筛下去了。因此,在满足i这个条件之前以及第一次满足改条件时,prime[j]必定是prime[j]i的最小因子

  
  

求欧拉函数

相关公式

x=Πpaii
φ(x)=x1 <xprime>
φ(x)=xΠ(11pi)=Π(pipai1i)
除此只外,欧拉函数还是积性函数,即φ(xy)=φ(x)φ(y) <gcd(x,y)=1>

  

代码

利用线性筛可以在线性时间内求得phi[i]

int tot_prime, prime[maxn], phi[maxn];
bool vist[maxn];
void get_prime(){

    phi[1] = 1;
    for(int i = 2; i <= n; ++i){
        if(!vist[i]) prime[++tot_prime] = i, phi[i] = i - 1;
        for(int j = 1; i * prime[j] <= n && j <= tot_prime; ++j){
            vist[i*prime[j]] = true;
            if(i % prime[j] == 0){
                phi[i*prime[j]] = phi[i] * prime[j];
                break;
            }
            else phi[i*prime[j]] = phi[i] * prime[j];
    }
}

  

what’s more

但有时并不需要求1...x的所有欧拉函数值,很多时候我们要求的都是一个比较大的数字x(x[1,109])的欧拉函数值
虽然不需要筛法求欧拉函数了,但根据公式,还是需要筛素数
以下是筛素数之后的代码

int phi(int x){

    int rtn = 1, cpy_x = x;
    for(int i = 1; prime[i] * prime[i] <= cpy_x && i <= tot_prime; ++i){

        int temp = 1;
        while(x % prime[i] == 0){
            x /= prime[i];
            temp *= prime[i];
        }
        if(temp > 1) rtn *= temp - temp / prime[i];
    }
    if(x > 1) rtn *= (x - 1); // 还剩下一个很大的质数

    return rtn;
}

  
  

求约数的个数

相关公式

f(x)x的约数的个数,还是把x表示成x=Πpaii的形式
f(x)=Π(ai+1)
f(x)=2 <xprime>
发现f(x)也是积性函数,即f(xy)=f(x)f(y) <gcd(x,y)=1>

  

代码

为了方便,让a[i]表示x最小素数因子的个数

int tot_prime, prime[maxn];
int f[maxn], a[maxn];
bool vist[maxn];
void get_f(){

    f[1] = 1;
    for(int i = 2; i <= n; ++i){

        if(!vist[i]) prime[++tot_prime] = i, f[i] = 2, a[i] = 1;
        for(int j = 1; i * prime[j] <= n && j <= tot_prime; ++j){
            vist[i*prime[j]] = true;
            if(i % prime[j] == 0){
                f[i*prime[j]] = f[i] / (a[i] + 1) * (a[i] + 2);
                a[i*prime[j]] = a[i] + 1;
                break;
            }
            else f[i*prime[j]] = f[i] * f[prime[j]], a[i*prime[j]] = 1;
        }
    }
}

  

一些解释

if(i % prime[j] == 0){
    f[i*prime[j]] = f[i] / (a[i] + 1) * (a[i] + 2);
    a[i*prime[j]] = a[i] + 1;
    break;
}

prime[j]i的约数时,iprime[j]就相当于i多了一个最小素因子,根据之前的公式,所以转移如上。

else f[i*prime[j]] = f[i] * f[prime[j]], a[i*prime[j]] = 1;

iprime[j]互质时,由积性知f[]转移如上。
对于a[]的转移,我是这样理解的:
我们先假设iprime[j]的最小素因子个数为1。
如果iprime[j]的最小素因子是由i提供的话,我们马上就会枚举到它的最小素因子,然后把a[iprime[j]]修改为正确的值。
否则iprime[j]的最小素因子就是prime[j]且不被i包含。这是因为首先i mod prime[j]!=0;其次,假设iprime[j]的最小素因子在i中,那么肯定早就break了,我们就不可能枚举到prime[j]

  
  

求莫比乌斯函数

相关公式

μ(x)=1 <x=1>
μ(x)=1k<x=Πki=1pi,pi1>
μ(x)=0<>
莫比乌斯函数同样是积性函数,即μ(xy)=μ(x)μ(y) <gcd(x,y)=1>

  

代码

mu[1] = 1;
for(int i = 2; i <= n; ++i){
    if(!vist[i]) prime[++tot_prime] = i, mu[i] = -1;
    for(int j = 1; i * prime[j] <= n && j <= tot_prime; ++j)
        vist[i*prime[j]] = true;
        if(i % prime[j] == 0){
            mu[i*prime[j]] = 0;
            break;
        }
        else mu[i*prime[j]] = mu[i] * mu[prime[j]];
}

参考与其他

线性筛(欧拉筛)
【数论内容】线性筛素数,线性筛欧拉函数,求前N个数的约数个数
莫比乌斯反演ppt by PoPoQQQ
xiaohao1大神的讲解与莫比乌斯反演pdf

欧拉函数
积性函数、线性筛、莫比乌斯反演和一堆乱七八糟的题目

版权声明:本文为博主原创文章,转载请注明出处。

相关文章推荐

线性筛素数——Homework(2015 Facebook Hacker Cup)

题目: Your first-grade math teacher, Mr. Book, has just introduced you to an amazing new concept — pr...
  • FeBr2
  • FeBr2
  • 2016-07-12 10:45
  • 160

积性函数的性质及证明 + 线性筛

引言在数论问题中,积性函数有着广泛的应用。 如在莫比乌斯反演问题中,函数变换之后如何快速维护前缀和往往是最重要也是最难的一步。如果维护的函数具有积性,那就可以尝试利用线性筛在O(n)O(n)的时限内...

POJ 2635 The Embarrassed Cryptographer 线性筛+高精度取模

题目大意:给两个数,第一个数的范文是10^100,第二个数10^6,第一个数是两个质数的乘积,问有没有不超过第二个数的数是第一个树的因子。 思路:10^6中只有7w+个素数,只要挨个判定能不...

bzoj4407 于神之怒加强版(莫比乌斯反演+线性筛)

4407: 于神之怒加强版 Time Limit: 80 Sec  Memory Limit: 512 MB Submit: 355  Solved: 174 [Submit][Status...

hdu 5780 gcd(线性筛+快速幂+数论)

题目描述传送门题目大意: ∑1<=a,b<=ngcd(xa−1,xb−1)\sum\limits_{1<=a,b<=n} gcd(x^a-1,x^b-1)题解首先对于gcd(xa−1,xb−1)gc...

欧拉线性筛求质数

欧拉线性筛求质数欧拉线性筛法。 不会重复筛除,是线性O(n)的复杂度。const int MAXN=3000001; int prime[MAXN];//保存素数 bool mark[MA...

线性筛与欧拉函数、莫比乌斯函数

网上关于素数筛的资料很多,这里只是给出弱鸟整理的几个线性筛和应用。最朴素的素数筛——埃拉托斯特尼筛法(Sieve of Eratosthenes) 复杂度 Olognlognint primes[M...
  • Joovo
  • Joovo
  • 2017-04-17 01:52
  • 543

线性筛素数

线性筛素数的总结。

POJ 2739 Sum of Consecutive Prime Numbers(线性素数筛+前缀和)

Sum of Consecutive Prime Numbers Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: ...

数论知识总结(乘法逆元,欧拉函数,线性筛,快速幂,快速乘等)

数论总结 内容:欧拉函数,欧拉定理,费马小定理,中国剩余定理,欧几里得定理,扩展欧几里得定理,逆元,线性筛、卡特兰数、快速幂、快速乘、矩阵乘法。欧拉函数:A={ x | 1 < =x < n...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)