线性时间内筛素数+欧拉函数+莫比乌斯函数

最近学习了一种筛素数的方法,能够在 O(n) 的时间内完成。
这个算法的核心思想是:每一个合数可以被唯一地表示成它的一个最小质因子和另外一个数的乘积。证明略。

void Init(){  
    ph[1]=1;  
    primes=0;  
    for (LL i=2;i<n;i++){  
        if (!vis[i]){  
            prime[primes++]=i;  
            ph[i]=i-1;  
        }  
        for (LL j=0;j<primes && i*prime[j]<n;j++){  
            vis[i*prime[j]]=1;  
            if(i%prime[j])  
                ph[i*prime[j]]=ph[i]*(prime[j]-1);
            else{  
                ph[i*prime[j]]=ph[i]*prime[j];  
                break;  
            }  
        }  
    }  
}  

通俗的说,就是对于每一个质数p,枚举i,删除i*p^1, i*p^2, i*p^3, …。

这个是筛素数的一个很原始的方案,也就是把质数的所有倍数删掉。看起来很暴力,但是很容易证明它的正确性,更容易证明它的时间复杂度是O(n)的:因为每一个元素最多被删除一次,并且没有新的元素插入集合中!

同时,也可以线性的求莫比乌斯函数

void init_mu(){   
    mu[1]=1;  
    primes=0;  
    for(int i=2; i<maxn; i++){  
        if(!vis[i]){  
            prime[primes++]=i;  
            mu[i]=-1;  
        }  
        for(int j=0; j<primes&&i*prime[j]<maxn; j++){  
            vis[i*prime[j]]=1;  
            if(i%prime[j]) 
                mu[i*prime[j]]=-mu[i];
            else {
                mu[i*prime[j]]=0;
                break;
            }  
        }  
    }  
}  

自然而然的,我们可以把这两个合并,就可以在线性时间内筛素数+求欧拉函数+求莫比乌斯函数~

void Init(){  
    ph[1]=1;
    mu[1]=1;    
    primes=0;  
    for (LL i=2;i<n;i++){  
        if (!vis[i]){  
            prime[primes++]=i;  
            ph[i]=i-1; 
            mu[i]=-1; 
        }  
        for (LL j=0;j<primes && i*prime[j]<n;j++){  
            vis[i*prime[j]]=1;  
            if(i%prime[j]){ 
                ph[i*prime[j]]=ph[i]*(prime[j]-1);
                mu[i*prime[j]]=-mu[i];    
            }
            else{  
                ph[i*prime[j]]=ph[i]*prime[j]; 
                mu[i*prime[j]]=0; 
                break;  
            }  
        }  
    }  
} 
                                  HelenKeller
                                  2016.7.9
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值