標籤:思路 擴充歐幾裡得 time 證明 最好 自然數 int 迴圈 ...
數論基礎算術基本定理(唯一分解定理)
任何一個大於1的自然數都可以唯一分解成有限個素數的乘積
$N=p_1^{a_1}\times p_2^{a_2}\times...\times p_n^{a_n} | p_1<p_2<...<p_n ,a_i\in Z$
上式中$p_i$為素數
有關素數篩
埃式篩法
就是拿一個已經篩選出的素數去排掉其他的數,比如2是素數,就用他篩掉2*2,2*3,2*4……,3是素數,就用他篩掉3*2,3*3,3*4……,把每個素數的倍數都篩掉,不過我們發現,3*2事實上已經在2的時候篩掉過了,即比這個數小的倍數都已經被篩過了,所以我們只要從這個數的平方開始篩就可以了。這個篩法最容易理解也最好寫,一定要會寫!經過這個篩法,能打素數表,能判定一個數是不是素數。複雜度O(nloglogn)。也可以用這種篩法篩出因子。
1 const int N=1e6+7; 2 bool isprime[N]; 3 int prime[N];//儲存素數,打表 4 void db() 5 { 6 memset(isprime,1,sizeof(isprime));//這步事實上不太好,不過因為是bool類型所以不影響結果 7 isprime[0]=isprime[1]=0; 8 int cntp=0; 9 for(long long i=2;i<N;i++)10 {11 if(isprime[i])12 {13 prime[cntp++]=i;14 for(long long j=i*i;j<N;j+=i)//i*i會爆int所以用ll15 isprime[j]=0;16 }17 }18 }埃式篩法
歐拉線性篩法
正常情況下就算是沒有最佳化的埃式篩法應該也是夠用的,但是我們發現埃式篩法還是不是最快的,比如12這個數會被2和3篩兩次,諸如此類的重複會降低效率。所以我們給出歐拉線性篩法。這個篩法自然比較難理解一點,其思路是這樣的,從2開始,將這個素數和之前篩出的所有素數的乘積都判負,如果碰到i是一個合數,也用他去篩,但在篩的迴圈中碰到一個是他因子的素數就跳出(一個合數必定能表示成至少一個素數參與的分解式),達到避免重複篩的目的,然後一個迴圈後就篩出了素數。這個方法比較難理解,我也不是很能感受到這個方法的正確性,不過據說用反證法能進行證明。複雜度O(n)。
線性篩還能用在處理其他積性函數上。
1 const int N=1e6+7; 2 bool isprime[N]; 3 int prime[N]; 4 void db() 5 { 6 memset(isprime,1,sizeof(isprime)); 7 isprime[0]=isprime[1]=0; 8 int cntp=0; 9 for(int i=2;i<N;i++)10 {11 if(isprime[i])12 prime[cntp++]=i;13 //這一部分是精髓所在也是難理解的部分,不管i是否是素數,都進迴圈去篩,i是合數時中途會跳出,達到減少重複篩的目的14 for(int j=0;j<cntp&&i*prime[j]<N;j++)15 {16 isprime[i*prime[j]]=0;17 if(!(i%prime[j]))18 break;19 }20 }21 }歐拉線性篩 有關因子
求因子個數
前置定理:若p是一個素數,a是一個正整數,那麼有$\tau(p^a)=a+1$。
定理:若正整數n有質因數分解$n=p_1^{a_1}\times p_2^{a_2}\times...\times p_k^{a_k}$,則$\tau(n)=(a_1+1)\times(a_2+1)\times...\times(a_k+1)$。
我們需要先打出一張素數表才能套用這個。
1 int factor_count(int n) 2 { 3 int ans=1; 4 int cnt; 5 int k=sqrt(n)+1; 6 for(int i=0;prime[i]<k;i++) 7 { 8 if(n%prime[i]==0) 9 {10 cnt=0;11 while(n%prime[i]==0)12 {13 cnt++;14 n/=prime[i];15 }16 ans*=(cnt+1);17 }18 }19 if(n>1)//這一步是因為只篩到根號n,可能會留最後一個因子,此時需要再算上這個因子20 ans*=2;21 return ans;22 }求因子個數
素因子篩
利用埃式篩法處理,複雜度O(nloglogn)
1 const int maxn=1e5+7; 2 void db() 3 { 4 vector<int> d[maxn]; 5 for(int i=2;i<maxn;i++) 6 if(d[i].empty()) 7 { 8 for(int j=2*i;j<maxn;j+=i) 9 d[j].push_back(i);10 }11 }素因子篩有關GCD
輾轉相除法
1 long long gcd(long long a,long long b)2 {3 return b?gcd(b,a%b):a;4 }GCD
擴充歐幾裡得
1 long long exgcd(long long a,long long b,long long &x,long long &y) 2 { 3 if(b==0) 4 { 5 x=1,y=0; 6 return a; 7 } 8 long long gcd=exgcd(b,a%b,y,x); 9 y-=a/b*x;10 return gcd;11 }exgcd
數論基礎學習總結(持續補充中)