模板整理:数论---线性筛素数,线性筛欧拉函数


线性筛是一个比较有用的东东,
所以得好好记住辣。。。
对于普通的筛素数方法,
就是枚举一个i,然后和所有已知素数prime[j]相乘,
i*prime[j]就不是素数了,去掉即可。
如果这样的话是基本O(nlogn)的,
线性筛就是在这个筛法的基础上加入了一个优化,
每次让一个数只被它的最小质因子筛一次,
也就是如果i%prime[j]=0,直接break即可。
这样的话就能优化到O(n)了,代码如下:

//notprime[i]=1表示i不是质数,不然表示i为质数
//prime[i]记录第i个素数,pcnt记录素数的个数
//MAX为最大值
void Get_Prime(){
    notprime[1]=1,pcnt=0;
    for (int i=2;i<MAX;i++){
        if (!notprime[i]) prime[++pcnt]=i;
        for (int j=1;j<=pcnt;j++){
            if (prime[j]*i>=MAX) break;
            notprime[prime[j]*i]=1;
            if (!(i%prime[j])) break;  //线性筛的重要优化
        }
    }
}


对于欧拉函数,根据它的定义式:

phi(n)=n(p11)(p21)...(pk1)/p1/p2/.../pk

那么对于一个n,可以在O(logn)的时间内计算phi(n),
如果要计算1~n的每个数的phi,就需要O(nlogn)的时间了;
然而其实求1~n每个数的欧拉函数是可以做到O(n)的,
就是在线性筛的基础上增加几句,,
这都基于欧拉函数的几个性质:
1. phi(i)=i1i
2. phi(iprime[j])=phi(i)prime[j],i%prime[j]=0
3. phi(iprime[j])=phi(i)(prime[j]1)i%prime[j]0
积性函数的一个东东啦。。
于是在线性筛素数的过程中我们也可以线性筛出欧拉函数了。
如果要欧拉函数求和,只要对phi做个前缀和就好辣!

//这里n是最大值
void get_eula_prime(){
    notprime[1]=1,pcnt=0;
    phi[1]=1;
    for (int i=2;i<=n;i++){
        if (!notprime[i]) phi[i]=i-1,prime[++pcnt]=i;
        for (int j=1;j<=pcnt;j++){
            if (i*prime[j]>n) break;
            notprime[i*prime[j]]=1;
            if (i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            } else phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}



线性筛素数是一直要用的,
而线性筛欧拉函数要看情况,有时候可能直接O(logn)会更优,
要适当选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值