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

来源:互联网 发布:demo软件 编辑:程序博客网 时间:2024/06/04 18:31


线性筛是一个比较有用的东东,
所以得好好记住辣。。。
对于普通的筛素数方法,
就是枚举一个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)会更优,
要适当选择。