欧拉线性筛求质数

欧拉线性筛求质数

欧拉线性筛法。

应用:

1.筛质数

不会重复筛除,是线性O(n)的复杂度。

const int MAXN=3000001;  
int prime[MAXN];//保存素数   
bool mark[MAXN];//初始化   
int Prime(int n)  
{  
    int cnt=0;  
    memset(mark,0,sizeof(mark));  
    for(int i=2;i<n;i++)  
    {  
        if(!mark[i])  
        prime[++cnt]=i;  
        for(int j=1;j<=cnt&&i*prime[j]<n;j++)  
        {  
            mark[i*prime[j]]=1;  
            if(i%prime[j]==0)//关键   
            break;  
        }  
    }  
    return cnt;//返回小于n的素数的个数   
}  

首先,先明确一个条件,任何合数都能表示成一系列素数的积。
然后利用了每个合数必有一个最小素因子,每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。
代码中体现在:
if(i%prime[j]==0)break;
prime数组 中的素数是递增的,当 i 能整除 prime[j],那么 i*prime[j+1] 这个合数肯定被 prime[j] 乘以某个数筛掉,因为某个数只会被它的最小的质因数更新,而这里不满足。
因为i中含有prime[j], prime[j] 比 prime[j+1] 小。接下去的素数同理。所以不用筛下去了。
在满足i%prme[j]==0这个条件之前以及第一次满足改条件时,prime[j]必定是prime[j]*i的最小因子。

例子:
比如当前i=15,那么其最小素因数是3,而且它可以表示成3*5;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
那么筛到这里也就可以停止了,因为i*prime[j+1],也就是5*15=75,一定会在当i=25时被其最小素因数3更新。

2.求欧拉函数

利用欧拉函数的性质( p为质数 ):
1. phi(p)=p-1
2. 如果i mod p = 0, 那么 phi(i * p)=p * phi(i)
3.若i mod p ≠0, 那么 phi( i * p )=phi(i) * ( p-1 )

以上两条均可以用欧拉函数的表达式推出E(n)=n*(1-1/p1)(1-1/p2)…*(1-1/pn) 其中px是n的质因数。)

void getPhi()
{
    int i,j,tot=0;
    for(i=2;i<=MaxN;i++)              
    {
        if(Mark[i]==false){  Prime[++tot]=i;phi[i]=i-1;  }
        //当 i 是素数时 phi[i]=i-1
        for(j=1; j<=tot&&i*Prime[j]<=MaxN; j++)                          
        {
            Mark[i*Prime[j]]=true;            
            if(i%Prime[j]==0)                                
            {   
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
//如果i mod p = 0, 那么 phi[i * p]=p * phi[i] 
            else   phi[i*Prime[j]]=phi[i]*(Prime[j]-1);
        }
        //其实这里Prime[j]-1就是phi[Prime[j]],利用了欧拉函数的积性  
        }             
}

3.求组合数取模(分解质因数法)Cnm mod p

以C64为例:
C64=(6!)/(4!×2!)=((2×3)×(5)×(2×2)×(3)×(2)) / ((2×2)×(3)×(2)×(2))

我们记录分子分母中对应质数的个数:分子:Pri[2]=4,Pri[3]=2,Pri[5]=1
分母:Pri’[2]=4,Pri’[3]=1
上下抵消,剩下Pri[3]=1,Pri[5]=1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值