所有**若無說明,均採用快讀模板
關於質數,無非就兩大類:
判斷乙個數字是不是質數
找出[1,n]中所有的質數
先講1:
判斷x是不是質數
根據質數的定義,我們可以列舉所有小於x,大於1的正整數i。如果x%i==0,即i是x的因數,則x不是質數。
很明顯,乙個質數的因數是成對出現,且分別在sqrt(x)的兩邊。所以只要列舉到sqrt(x)即可。
bool judge(ll &x)時間複雜度o(sqrt(n))return1;
}
那麼,這裡插一句嘴——只要再從1~n列舉乙個數,不就可以得出1~n中所有的質數了嘛?!
(另外一種判斷質數的方法等會再講)
上面是指極限下1s能過的資料
bool judge(ll & x)//時間複雜度o(nsqrt(n))n=1.5*10^6 這裡用il反而會慢0.01s
return1;
}ll n;
intmain()
return0;
}
這裡只要把上面的那個n=1.5*10^6做乙個小小的優化(可以理解為記憶化)
其實,我們在嘗試列舉因數的時候,我們可以只要列舉質因數就好。
比如x=91
如果我列舉到i=2(某個質數)發現不能整除,那麼91當然也不能被2的倍數(質數的(2倍以上的)倍數是不是質數)整除啊
所以,judge()中的列舉i只需要列舉1~sqrt(x)中的質數即可。
使用乙個陣列儲存所有的質數吧。
ll his[1000000時間複雜度o(?)];ll size;
bool judge(ll & x)//
n=4*10^6
return1;
}ll n;
intmain()
return0;
}
接下來在看看
這次是埃氏篩(埃拉託斯特尼篩法)。
每找到乙個質數,就將它的倍數打上標記即可。
如果迴圈到某個數的時候,它沒有被打上標記
那麼它就一定是質數了,
就再拿它去更新它的倍數。
bool book[30000000時間複雜度o(nloglogn),已經非常接近於線性的了];ll prime[
30000000
];ll size;
ll n;
int main()//
n=3*10^7}}
return0;
}
(注意,雖然它的影象在10000以內的斜率看似比y=x還要小,但是我們比較的是其增長性,即:nloglogn的導數是單調遞增的)
可能一階導看不出來
紫色:nloglogn
紅色:f'(x)
藍色:f''(x)
好了,不管那麼多了,再看這次最強的篩法:尤拉篩 吧
n=3*10^7(***)
請先思考一下
為什麼埃氏篩會超過線性呢?
因為其實,乙個合數可能會被打上多次的合數標記
比如,列舉到2是質數的時候,會把4、6、8、10……打上標記
列舉到3是質數的時候,會把6、9、12……打上標記
然後6就被打了兩次標記。
有乙個更加嚴重的例子,一些合數甚至被打了很多次,這就浪費了很多次的機會,比如60
60這個數字被它的質因數們:2、3、5打了標記
而510510被它的質因數們:2、3、5、7、11、13、17打了標記。。。
浪費的時間就在這裡了。。。
那麼,尤拉篩:
#define maxn 50000000ll prime[maxn];一樣的套路。bool
book[maxn];
ll n,size;
intmain()
}return0;
}
首先一定要記憶化(儲存prime陣列)
其次無論當前的數是不是質數都要用這個數字i向後篩
但是僅僅篩到i%prime[j]==0,即i可以被從小到大的某個質數整除為止。
所以,對於乙個i,第二層for僅僅會篩到它的最小質因數倍的i
即比如i=5,就只會篩走2*5,3*5,5*5(然後5%5==0 -> break;)
所以每個數隻會被它的最小質因數篩——只會被篩一遍
所以它的時間複雜度是o(n)的
如果你還是不信:
#define maxn 50000000ll prime[maxn];驗證bool
book[maxn];
ll n,size;
intmain()
}return0;
}
![](https://pic.w3help.cc/10a/29572cd0be2866814fac17f23b03a.jpeg)
被篩的數字是不會相同的。
咦?那這個演算法1s極限怎麼和高貴的埃氏篩相差無幾(明明是根本一樣好吧!)啊~因為它有一定的常數(用到了取模),還一定要儲存質數(這個影響不大)
但是,在更大的資料下,尤拉篩才能展現出其真正的魅力!
比如說這個資料:
200'000'000(2*10^8,兩億)看上去就很不錯
用埃氏篩來跑,需要3.682s左右
但是用尤拉篩,只需要2.943s左右!
(以上資料為無輸出資料,且僅用於對比,無實際意義)
所以以後考試的時候還是打埃氏篩吧——又簡單常數又小!
最後——
快速的大質數判斷,基於隨機演算法。
可以在o(klogn)內判斷乙個數字是不是質數,其中k為判斷的次數(稍後你就懂了),n是這個數字的大小。
我不太懂它的證明過程,但是我覺得我這麼菜,只要會用就好了……
以下是步驟:
f是乙個小質數,a是要測試的數字,d=a-1
去除d的因數2(即把d除以二直到d變成奇數)
計算t=f^d%a(快速冪)
迴圈直到d=a-1或t=1或t=a-1
這時如果t==a-1或者d是奇數,那麼可以粗劣地判斷a是質數
多選幾個f判斷,同時滿足的話,就可以說是質數了
關於質數的一些演算法
首先是基礎中的基礎,怎麼判斷乙個數是不是質數,直接試除就行了,只需要嘗試到sqrt n 因此時間複雜度o n 1 2 public static boolean isprime long number 其次是篩法,也就是從乙個範圍內篩選出質數,最直接的辦法是乙個個判斷,這顯然很複雜,因此有了篩法的概...
關於hash質數
最近我在做乙個專案,其中要用到乙個資料結構 hash table 雜湊表 以前只有理論知識,現在實卻發現很不簡單,所以寫下來和大家共分享。我們知道,雜湊表是乙個固定大小的陣列,陣列的每個元素是乙個鍊錶 單向或雙向 的頭指標。如果key一樣,則在一起,如果key不一樣,則不在一起。雜湊表的查詢是飛快的...
關於質數(素數)
素數的演算法 最基礎的演算法 n int input for i in range 2,n if n i 0 print n,可以被 i,整除 break else print n,是乙個質數 改進演算法,通過開方縮小整除範圍 n int input for i in range 2,int n 0...