素数线性筛、欧拉函数线性筛

这俩算法,可以在线性时间内,筛素数的同时,求出所有数的欧拉函数。

参考博客:

素数线性筛原理:https://www.cnblogs.com/xiaodeshan/p/7811344.html

素数线性筛代码实现:https://blog.csdn.net/litoupu/article/details/11020885

素数线性筛  扩展到  欧拉函数线性筛:https://blog.csdn.net/pengwill97/article/details/77509425

 

一、线性素数筛

线性素数筛原理:

原始的埃氏筛选法,效率已经不低了,但是会有很多的重复计算,即一个数会被多次踢出,浪费了计算时间。

现在,线性素数筛,可以保证,每个合数只被踢出一次。

即,保证每个合数,都被其最小的质因数筛去。

 

实现方法是:

如果当前数 i,被发现可以整除某个已经确定了的质数,那么当前数 i 就不必再往下看了,直接break,进入下一个数。

 

为什么可以这样做呢?

因为这样一来,当前数 i 就可以被确定是一个合数;

任意一个合数和一个质数的乘积,都可以用一个更大的合数和一个更小的质数的乘积表示;

当前数 i 本来可以构成的所有合数( i*prime[0] , i*prime[1] , i*prime[2] ……),都肯定之前已经被踢出过了,不必再重复计算了

 

(每个合数必有一个最小素因子,每个合数肯定能够由素数的相乘得到。)

(每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。)

 

线性素数筛模板:

bool is_prime[MAX];   //记录每个数是否为素数
void makePrime2()
{
    vector<int> prime;    //存储到现在为止,所有已经确定的素数
    memset(is_prime,0,sizeof(is_prime));
    for(int i=2;i<=MAX;i++)    //从i=2开始(乘两倍起步)
    {
        if(is_prime[i]==0)
            prime.push_back(i);
        
        for(int j=0; j<prime.size() && i*prime[j]<=MAX; j++)   //最大筛到MAX为止
        {
            is_prime[i*prime[j]]=1;
            if(i%prime[j]==0)
                break;
        }
    }
}

 

 

 

解释:

1:各个数组的意义:

     is_prime [MAX]:记录每个数是否为素数

     vector<int> prime:  存储到现在为止,所有已经确定的素数

2:最外层for循环的意义:

     i=2 就表示,所有现在已经确定的素数(vector prime 里面所有的数),每一个都乘2,所得的数,全部筛掉

     i=3 就表示,所有现在已经确定的素数,每一个都乘3,所得的数,全部筛掉

     …………

3:请注意第十五行的  break ,这里是精髓。

     具体为什么写,见上方“线性素数筛原理”。

 

 

 

 

二、欧拉函数线性筛

 

欧拉函数线性筛原理:

欧拉函数线性筛,代码基本和素数线性筛一样,只不过是在筛出素数的时候,顺便在同时,筛出各个数的欧拉函数值

 

利用素数合数信息,推出欧拉函数值的方法:(欧拉函数的几条性质)

1:当n为质数的时候,φ(n)=n1

2:欧拉函数是积性函数,但不是完全积性。当n,m互质的时候,φ(nm)=φ(n)φ(m) 

 

(其实欧拉函数还有以下一些性质,不过他们与此次博文主题不相关)

3:当n为奇数的时候,φ(2n)=φ(n)

4:除了φ(2)时,其他欧拉函数均为偶数。

5:小于n,且与n互质的所有数字的和是φ(n)n/2

 

 

线性欧拉筛的代码模板:

 

 

(在素数线性筛的基础上改造,一边筛选素数,一边顺便利用性质,算出每个数的对应的欧拉函数值)

 

vector<int> prime;    //记录看到现在为止的每个素数
bool is_prime[maxn+5];    //记录每个数是否是素数
int phi[maxn+5];     //存储每个数对应的欧拉函数值
void init()
{
    memset(is_prime,0,sizeof(is_prime));
    
    phi[1]=1;   //赋初始值:phi[1]=1;
    for(int i=2;i<=maxn;i++)
    {
        if(is_prime[i]==0)
        {
            prime.push_back(i);
            phi[i]=i-1;     //参考性质1
        }
        
        for(int j=0;j<prime.size() && i*prime[j]<=maxn;j++)
        {
            is_prime[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);   //参考性质2
            }
        }
    }
    
}

 

 

欧拉的应用实例:

http://acm.hdu.edu.cn/showproblem.php?pid=6434

 

posted on 2018-09-12 13:45  _isolated  阅读(161)  评论(0)    收藏  举报