數論線性篩總結 (素數篩,尤拉函式篩,莫比烏斯函式篩,前n個數的約數個數篩)
線性篩
線性篩在數論中起著至關重要的作用,可以大大降低求解一些問題的時間複雜度,使用線性篩有個前提(除了素數篩)所求函式必須是數論上定義的積性函式,即對於正整數n的一個算術函式 f(n),若f(1)=1,且當a,b互質時f(ab)=f(a)f(b),在數論上就稱它為積性函式,若a,b不互質也滿足的話則稱作完全積性函式,下面說明每個篩子是怎麼篩的。
最基礎的是素數篩,其它三個篩都是以素數篩為前提
素數篩
void get_prime()
{
int pnum = 0;
for(int i = 2; i < MAX; i++)
{
if(!noprime[i])
p[pnum ++] = i;
for(int j = 0; j < pnum && i * p[j] < MAX; j++)
{
noprime[i * p[j]] = true;
if(i % p[j] == 0)
break;
}
}
}
主要是break那裡,比如12這個數,在普通篩的時候12要被2和3都篩一次,顯然這種多餘的操作會增加時間複雜度,線性篩中一個數字只被它最小的素因子篩掉,12只被2篩掉,當i等於6的時候2*6==12篩掉12,這時候6%2==0可以break了,如果不break,那麼6還會把18篩掉,此時是通過6*3來篩掉18,可是顯然18最小的素因子是2,所以當i列舉到9的時候有9*2==18,這樣18就又被篩了一次,因此在i等於6的時候不用拿6去篩18,下面用公式來說明:
當p[j]是i的因子時,設i=p[j]*k,因為素因子從小到大列舉,所以p[j]是i的最小素因子,此時i已經無需再去剔除p[j']*i (j'>j) 形式的合數了,因為p[j']*i可以寫成p[j']*(p[j]*k)=p[j]*(p[j']*k),也就是說所有的p[j']*i將會被將來的某個i'=p[j']*k剔除掉,當前的i已經不需要了。
尤拉函式篩
尤拉函式phi[i]表示的是與1-i中與i互質的數的個數。
求解時分三種情況:
1.當i為素數時,顯然phi[i] = i - 1
2.當i % p[j] != 0時,gcd(i, p[j]) = 1,由積性函式的性質可得phi[i * p[j]] = phi[i] * phi[p[j]] = phi[i] * (p[j] - 1) (p陣列表示素數)
3.當i % p[j] ==0時,根據尤拉函式的求法:phi[n] = n * ∏(1 - 1/p),p為n的質因子,故若i % p[j] == 0,i * p[j]的質因子數不變
則phi[i * p[j]] = i * p[j] * ∏(1 - 1/p) = p[j] * i * ∏(1 - 1/p) = p[j] * phi[i]
由此得到尤拉函式篩:
void get_eular()
{
pnum = 0;
for(int i = 2; i < MAX; i++)
{
if(!noprime[i])
{
p[pnum ++] = i;
phi[i] = i - 1;
}
for(int j = 0; j < pnum && i * p[j] < MAX; j++)
{
noprime[i * p[j]] = true;
if(i % p[j] == 0)
{
phi[i * p[j]] = phi[i] * p[j];
break;
}
phi[i * p[j]] = phi[i] * (p[j] - 1);
}
}
}
莫比烏斯函式篩
莫比烏斯函式mob[i]
若i為奇數個不同素數之積mob[i] = -1
若i為偶數個不同素數之積mob[i] = 1
若i有平方因子則mob[i] = 0。
這個做起來比尤拉函式容易,在素數篩上,若i為素數則mob[i] = -1,若i % p[j] == 0,則mob[i * p[j]] = 0,顯然p[j]就是它的平方因子,否則mob[i * p[j]] = -mob[i]
由此得到莫比烏斯函式篩:
void Mobius()
{
int pnum = 0;
mob[1] = 1;
for(int i = 2; i < MAX; i++)
{
if(!noprime[i])
{
p[pnum ++] = i;
mob[i] = -1;
}
for(int j = 0; j < pnum && i * p[j] < MAX; j++)
{
noprime[i * p[j]] = false;
if(i % p[j] == 0)
{
mob[i * p[j]] = 0;
break;
}
mob[i * p[j]] = -mob[i];
}
}
}
前n個數的約數個數篩
facnum[i]表示i的約數個數
通過素數篩得到前n個數的約數個數非常巧妙,首先根據約數個數定理:
對於一個大於1正整數n可以分解質因數:n = p1^d1 + p2^d2 + ... + pk^dk,其中pi為素數
則n的正約數的個數就是
:facnum[n] = (1 + d1) * (1 + d2) * ... * (1 + dk)
我們需要一個輔助陣列d[i],表示i的最小質因子的次冪,(最小的原因是素數篩裡每次都是用最小的質因子來篩合數的),還是三種情況:
1.當i為素數時,facnum[i] = 2;d[i] = 1,很好理解
2.當i % p[j] != 0時,gcd(i, p[j]) =1,由積性函式的性質可得facnum[i * p[j]] = facnum[i] * facnum[p[j]] = facnum[i] * 2
d[i * p[j]] = 1(無平方因子)
3.當i % p[j] == 0時,出現平方因子,最小質因子的次冪加1,因此有facnum[i * p[j]] = facnum[i] / (d[i] + 1) * (d[i] + 2)
d[i * p[j]] = d[i] + 1
由此得到前n個數的約數個數篩:
void get_facnum()
{
int pnum = 0;
facnum[1] = 1;
for(int i = 2; i < MAX; i++)
{
if(!noprime[i])
{
p[pnum ++] = i;
facnum[i] = 2;
d[i] = 1;
}
for(int j = 0; j < pnum && i * p[j] < MAX; j++)
{
noprime[i * p[j]] = true;
if(i % p[j] == 0)
{
facnum[i * p[j]] = facnum[i] / (d[i] + 1) * (d[i] + 2);
d[i * p[j]] = d[i] + 1;
break;
}
facnum[i * p[j]] = facnum[i] * 2;
d[i * p[j]] = 1;
}
}
}
四合一
void get_all()
{
int pnum = 0;
phi[1] = 1;
mob[1] = 1;
facnum[1] = 1;
for(int i = 2; i < MAX; i++)
{
if(!noprime[i])
{
phi[i] = i - 1;
mob[i] = -1;
p[pnum ++] = i;
facnum[i] = 2;
d[i] = 1;
}
for(int j = 0; j < pnum && i * p[j] < MAX; j++)
{
noprime[i * p[j]] = true;
if(i % p[j] == 0)
{
phi[i * p[j]] = phi[i] * p[j];
mob[i * p[j]] = 0;
facnum[i * p[j]] = facnum[i] / (d[i] + 1) * (d[i] + 2);
d[i * p[j]] = d[i] + 1;
break;
}
phi[i * p[j]] = phi[i] * (p[j] - 1);
mob[i * p[j]] = -mob[i];
facnum[i * p[j]] = facnum[i] * 2;
d[i * p[j]] = 1;
}
}
}
最後吐槽一下,對於素數篩裡的判斷函式,最好用noprime,因為全域性預設值為false,有的時候MAX為1e7之類的,memset成true也費不少
python 素數篩
n = raw_input()
n = int(n)
isPrime = [True] * (n + 1)
prime = [0] * (n + 1)
cnt = 0
isPrime[0] = isPrime[1] = False
for i in range(2, n) :
if isPrime[i] :
prime[cnt] = i
cnt = cnt + 1
for j in range (0, cnt) :
if (i * prime[j] > n) :
break;
isPrime[i * prime[j]] = False;
if (i % prime[j] == 0) :
break
for i in range(0, cnt) :
print prime[i]
相關文章
- 素數個數 <埃式篩 && 尤拉篩>
- 尤拉篩線性篩質數
- 【數論】素數篩法
- 質數篩
- 約束定理+質數篩
- [演算法]: 素數篩法演算法
- 平凡的函式 線性篩積性函式函式
- Find Terrorists(素數篩選+素因子分解)Error
- POJ 2262 Goldbach's Conjecture (求解素數的一般篩和線性篩)Go
- 洛谷P3383 【模板】線性篩素數
- Diff-prime Pairs(思維+素數篩)AI
- 尤拉篩
- 篩選法求質數
- 尤拉素數篩選與命令列傳參啟動C程式命令列C程式
- 質數判斷、質因子分解、質數篩
- Codeforces 893E Counting Arrays:dp + 線性篩 + 分解質因數 + 組合數結論
- 用q實現篩法求1-n的質數
- 面試官本拿求素數搞我,但被我優雅的“回擊“了(素數篩)面試
- ACdream 1112 Alice and Bob (博弈&&素數篩選優化)優化
- HDU 4279 2012網路賽Number(數論 尤拉函式結論約數個數)函式
- 正規表示式實現的從字串中篩選出數字字串
- 面試官本拿求素數搞我,但被我用素數篩優雅的“回擊“了面試
- 增補部落格 第二十篇 python 篩法求素數Python
- Android開商品屬性篩選與商品篩選Android
- excel怎麼篩選?教你一個簡單粗暴的篩選技巧Excel
- 【開發篇sql】 分析函式(二) 行篩選相關的函式SQL函式
- 素數計數函式函式
- MYSQL 一個巧用字元函式巧用字元函式做資料篩選的題MySql字元函式
- 杜教篩
- js從字串中篩選出數字程式碼例項JS字串
- SQL Server 2008 引數化行篩選器SQLServer
- 篩選數十億化合物庫,華盛頓大學藥物AI虛擬篩選平臺,登Nature子刊AI
- HDU 4542 小明系列故事——未知剩餘系 (DFS 反素數 篩子預處理)
- min_25篩題目總結
- 電影裡的程式碼之《機械姬》:篩法求質數
- jQuery 篩選方法jQuery
- 動態篩選
- 表示素數的函式函式