由素數篩法到歐拉函數(歐拉函數,線性篩)


前言

蒟蒻最近准備狂補數學啦TAT

基於篩素數,可以同時快速求出歐拉函數。於是蒟蒻准備從這里入手,整理一下實現的思路。

篩素數及其一種改進寫法

傳統篩素數的做法(埃式篩)是,利用已知的素數,去篩掉含有此質因子的合數,十分巧妙。由於不是本文的重點,就只貼一下代碼吧

#include<cstdio>
#include<cmath>
#define R register int
const int N=100000000,SQ=sqrt(N);
bool f[N];
int main(){
	R i,j;
	for(i=2;i<=SQ;++i){
		if(f[i])continue;
		for(j=i<<1;j<N;j+=i)f[j]=1;
	}
	/*for(i=2;i<N;++i)
		if(!f[i])printf("%d\n",i);*/
	return 0;
}

復雜度不會證,不過較近似於線性(大概是\(O(n\log\log n)\)的樣子)。

實際上蒟蒻打了個表,N與篩的次數大概有這樣的關系

為什么是近似的呢?因為每個合數會被其多個質因子都篩一遍,所以並不是嚴格的。

於是我們要想辦法讓每個合數只被篩掉一次。如何實現呢?我們可以讓每個合數都只被其最小質因子篩掉(歐拉篩)。

與上面相比,這種新的更加優秀的寫法有了較大的變化。代碼如下,可結合注釋理解,也不多討論。

#include<cstdio>
#include<cmath>
#define R register int
const int N=100000000,B=N>>1;
bool f[N];
int pr[B];
int main(){
	R i,j,p=0;
	for(i=2;i<=B;++i){
		if(f[i])
			for(j=1;j<=p&&i*pr[j]<N;++j){
				f[i*pr[j]]=1;
				if(!(i%pr[j]))break;//這一句話就是使得每個合數只被最小質因子篩掉的關鍵
//簡要解釋一下,如果pr[j]|i,那么i就有一個質因子pr[j]
//那么{i*pr[j+k],k∈N*}的最小質因子就是pr[j]而不是pr[j+k]了
			}
		else{
			pr[++p]=i;
			for(j=1;j<=p&&i*pr[j]<N;++j)
				f[i*pr[j]]=1;//i是質數,所以可以省掉上面那個判斷,減小常數
		}
	}
	/*for(i=2;i<N;++i)
		if(!f[i])printf("%d\n",i);*/
	return 0;
}

實際運行\(N=10^8\)比上面那種寫法快一半。

歐拉函數

定義及性質

對一個正整數\(x\)定義歐拉函數\(\phi(x)\),為\([1,x]\)中與\(x\)互質的整數個數。

幾個基本內容(下面定義\(p\)為質數):

  1. \(\phi(1)=1\),這個沒啥好說的,因為本來就定義\(1\)\(1\)互質
  2. \(\phi(p)=p-1\),也是很顯然的,由質數定義得出
  3. 如果\(p|x\),那么\(\phi(x*p)=\phi(x)*p\),否則\(\phi(x*p)=\phi(x)*(p-1)\)。證明的話百度一下吧,蒟蒻不會qwq

這樣的話,是不是可以像埃式篩一樣,通過某個質數篩去質因子含這個數的合數的同時,計算出這個合數的歐拉函數值呢?好像是不行的,因為可能兩個數的商的歐拉函數值還沒求出來。

這時候,更好的歐拉篩又派上了用場。枚舉\(x\)再枚舉質數\(p\),這時候\(\phi(x)\)\(\phi(p)\)肯定都求出來啦,那么\(\phi(x*p)\)當然也就求出來啦。

#include<cstdio>
#define R register
const int N=1000001;
int pr[N],phi[N];
bool f[N];
int main(){
	R int n,i,j,k,p=0;
	phi[1]=1;//內容1
	for(i=2;i<N;++i){
		if(!f[i])phi[pr[++p]=i]=i-1;//內容2
		for(j=1;j<=p&&(k=i*pr[j])<N;++j){
			f[k]=1;
			if(i%pr[j])//內容3
				phi[k]=phi[i]*(pr[j]-1);
			else{
				phi[k]=phi[i]*pr[j];
				break;
			}
		}
	}
	return 0;
}

題目

一道模板題及其Sol


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM