欧拉筛法 && 欧拉函数

欧拉筛

对于O(nlognlogn)的埃拉特斯特尼筛法:

>for(int i=2;iif(!vis[i])
        {
           prime[cnt++]=i;//保存素数 
           for(int j=i*i;j//i*i开始进行了稍微的优化
           vis[j]=1;//因为 i 为素数 所以 i 的倍数  都是 合数 
        }
    }

可以发现有被重复筛到的数比如30 =2 * 15 =3 * 10 = 5* 6

欧拉筛就巧妙地让每个数都只被最小的质因子筛掉从而使复杂度变为O(n)

    for(int i=2;i<=maxn;i++)
    {
        if(!notprime[i])
        {
            prime[++cnt]=i;//统计质数
        }
        for(int j=1;j<=cnt&&prime[j]*i<=maxn;j++)
        {
            notprime[i*prime[j]]=1;
            if(i%prime[j]==0)//这里是精髓
                break;
        }
    }

通过

if(i%prime[j]==0)

这一句就实现了保证每个数只其最小质因子被筛一次
为啥?
对于一个数 a 假设它可以整除prime[ j ]
即 a= prime[ j ] * x
那么 a* prime[ j +1 ] = prime[ j ]* x * prime[ j+1 ]
所以 j 再往后就 没有必要筛了
因为a*prime[ j+1 ] 肯定会在 i= x * prime[ j+1 ]的时候被prime[ j ]筛掉

比如对于 i = 6 时
可以知道 6 = 2 * 3
那么 j=1 即 prime[ j ] = 2 时 2 * 6 = 12 被筛掉并退出循环
此时3 * 6 = 18并不会被筛掉因为18 = 3 * 2 * 3
所以后来当i= 9时 才会筛掉2 * 9 =18

欧拉函数

定义:在数论中,对正整数n,欧拉函数是小于或等于n的数中与n**互质**的数的数目。
分几种情况

  1. 当n为质数时 phi( n ) = n-1因为质数的因数只有1和本身

  2. 若n为质数p的k次方 那么 phin=pkpk1=pk(11p)
    因为只有当一个数不包含质数p才可能与n互质,而包含质数p的数一共有 1×p,2×p,3×p,...pp1×p pk1

  3. 若n为两个质数p1 p2 的乘积: 如果a与p1互质(a < p1),b与p2互质(b < p2),c与p1p2互质(c < p1p2),则c与数对 (a,b) 是一一对应关系。由于a的值有φ(p1)种可能,b的值有φ(p2)种可能,则数对 (a,b) 有φ(p1)φ(p2)种可能,而c的值有φ(p1p2)种可能,所以φ(p1p2)就等于φ(p1)φ(p2)。有

    phi(n)=pk1×pk2×(11p1)(11p2)=n×(11p1)(11p2)
    (欧拉函数的积性性质)
    ————若ab互质,则phi(a* b)=phi(a)*phi(b)

    因为任意一个大于1的正整数都可以写成一系列质数的乘积
    根据上面的性质可以推得

    n=p1×p2×...×pn (p均为质数)
    那么 phi(n)=p1×p2×...×pn×(11p1)(11p2)...(11pn)=n×(11p1)(11p2)...(11pn)

所以利用欧拉函数的性质:

可以得到:

设p为质数
如果p为x的因数
那么 phi(p×x)=p×x×(11p1)×...×(11pn)=phi(p)×x
如果p不是x的因数 即 p x互质
那么 phi(p×x)=phi(p)×phi(x)=phi(x)×(p1)

那么我们可以在筛质数的同时O(n)求出1~n的Eular函数值

具体实现如下:

for(int i=2;i<=maxn;i++)
    {
        if(!isprime[i])
        {
            prime[++cnt]=i;
            phi[i]=i-1;//质数直接能求出
        }
        for(int j=1;j<=cnt&&prime[j]*i<=maxn;j++)
        {
            isprime[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];//px不互质
                break;
            }
            else phi[i*prime[j]]=phi[i]*(prime[j]-1);//px互质
        }
    }

收工啦~

你可能感兴趣的:(一些算法)