欧拉筛(线性筛)& 欧拉函数

来源:互联网 发布:猴子吃桃问题c语言 编辑:程序博客网 时间:2024/06/05 09:23

今天又复习了一下欧拉筛法,在这做个笔记。

欧拉筛(线性筛)

一般情况下,有一种筛法叫埃什么什么的。是O(nloglogn),非常接近于O(n),但也会有坑爹的出题人来个10000000故意卡你。

原理

这可能原理有点妙啊。

  • pr[i]为i最小质因子,然后从2开始计算
  • 如果pr[i]没有在前面得到,就说明i是质数,所以pr[i]=i,prime[++len]=i
  • 对于i,枚举每一个不超过pr[i]的质数prime[j],所以pr[iprime[j]]=prime[j]

这样可以发现,每一个数只会被它最小的质因子筛去,所以保证了算法为O(n)的。

我们见一下代码:

代码

void find_prime(int n){    memset(isprime,0,sizeof(isprime));    sp = 0;    for(int i = 2;i <= n;i++)    {        if(!isprime[i])        {            prime[++sp] = i;            isprime[i] = i;        }        for(int j = 1;j <= sp && i * prime[j] <= n;j++) {            isprime[i*prime[j]] = prime[j];            if(prime[j] >= isprime[i]) break;//用isprime[i]来表示i的最小质因子,可能用mod比较慢         }    }}

在break那一行,有的人会用
      if(i % prime[j]==0) break;
不过也可以通过isprime[i]保存i最小的质因子来与prime[j]做比较。
但不管怎么写,我人认为最重要的就是含break的那个语句

欧拉函数

不过,仅仅筛素数就显得线性筛不是那么必要。
线性筛最科学的战场——求积性函数
作为蒟蒻,我以欧拉函数来举例:

代码

先粗浅地看一下代码

void find_prime(int n){    memset(isprime,0,sizeof(isprime));    sp = 0;    for(int i = 2;i <= n;i++)    {        if(!isprime[i])        {            prime[++sp] = i;            isprime[i] = i;            phi[i] = i-1;//①        }        for(int j = 1;j <= sp && i * prime[j] <= n;j++) {            isprime[i*prime[j]] = prime[j];            if(prime[j] >= isprime[i]) {                phi[i*prime[j]] = phi[i]*prime[j];//②                break;            }            phi[i*prime[j]] = phi[i]*(prime[j]-1);//③        }    }}

原理

  1. 每个数字只会被筛到一次
  2. 当正整数p为素数时,phi[p]=p1
  3. 欧拉函数既然是积性函数,就说明当a与b互质时,满足phi(ab)=phi(a)phi(b)
  4. 当p为素数时, phi(pk)=(p1)pk1
  5. 我们保证了每次的prime[j]小于等于i的最小质因子,所以当prime[j]<isprime[i]时,phi[iprime[i]]=phi[i]phi[j]=phi[i](j1),而在i%prime[j]==0时,直接乘上prim[j]

上述的五点:1表明每个数值被算一次。2解释了①。3、4、5解释了②和③。

还有,本文参考:http://www.cnblogs.com/zhuohan123/p/3233011.html

1 0
原创粉丝点击