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

(3) 2024-04-18 12:23

Hi,大家好,我是编程小6,很荣幸遇见你,我把这些年在开发过程中遇到的问题或想法写出来,今天说一说欧拉筛(线性筛)& 欧拉函数,希望能够帮助你!!!。

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

欧拉筛(线性筛)

一般情况下,有一种筛法叫埃什么什么的。是 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

今天的分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

上一篇

已是最后文章

下一篇

已是最新文章

发表回复