模板整理:數論---線性篩素數,線性篩歐拉函數


線性篩是一個比較有用的東東,
所以得好好記住辣。。。
對於普通的篩素數方法,
就是枚舉一個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)會更優,
要適當選擇。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章