素數判別
1.O(x) [根本不用]
2.sqrt判別 O(√N)
如果x可以表示為兩個因子相乘
x=a*b 假設a<=b
那么x>=a*a
a<=√x
只需要枚舉a<=√x就可以了
3.Miller-Rabin 素性測試
素性測試:
一個素數n,除了2,n-1 一定為偶數
a 屬於(1,n-1 ),n是素數
條件1, 2 至少有一成立
Ps:s.t.使得
Longlong范圍內測試這8個質數一般不會錯
代碼見下:
#include<iostream>
#include<cstdio> #include<cmath> #include<algorithm> #include<string> #include<cstring> #include<cstdlib> using namespace std; int gg[8] = {2,3,5,7,13,29,37,89}; int quickpow(int a,int b,int n) { int ans=1; while(b) { if(b%2==1) ans=ans*a%n; a=a*a%n; b/=2; } return ans; } bool miller_rabin(int a,int n) //判斷能否通過 { int d=n-1,r=0; while (d%2==0) d/=2,r++; int x = quickpow(a,d,n); if (x==1) return true; for (int i=0;i<r;i++) { if (x==n-1) return true; x=(long long)x*x%n; } return false; } bool is_prime(int n) //Is-prime判斷是否為素數
{
if (n<=1) return false; //特判 for (int a=0;a<8;a++) if (n==gg[a]) return true; for (int a=0;a<8;a++) if (!miller_rabin(gg[a],n)) return false; return true; } int main() { long long N; cin>>N; if(is_prime(N)) cout<<"Prime"<<endl; else cout<<"Not Prime"<<endl; return 0; }
素數篩法
求1—n中所有質數
可以帶入判素數 O(n√n) 但是會炸
1.未知名篩法
先假定所有數字都是質數
一個數的倍數一定不是質數,標記為合數
最后沒有被標記的,就是質數,因為不存在一個數i使得數i的倍數為這個數
算法復雜度達不到n2
b的枚舉次數:
2.埃式篩法 O(nloglogn) 篩法
合數的倍數一定會在篩素數倍數時候被篩掉
所以只篩素數就好,只把質數的素數篩掉
就是找到一個質數,把它的倍數全部標記為合數(但是你會發現有的數字會被標記多次,比如 6 被 2,3都標記,這樣會浪費時間。。)
Ps: 1+1/2+1/3+1/4+......+1/n (調和級數) 這樣的時間復雜度是 log n
然后你發現埃氏篩好浪費哦!!!我們下面看線性篩,保證每個數只被它的最小質因子標記為合數
3.線性篩法(歐拉篩)
P3383 【模板】線性篩素數
線性篩法保證了每個數只會被他的最小質因子標記 復雜度降O(n)
就是這么一個意思,我們要篩1~n中的素數
然后先默認他們都是素數
最外層枚舉1~n的所有數
如果它是素數,就加到素數表
對於每一個枚舉的i ,枚舉素數表里的數,然后素數就會標記自己 i 倍的數不是素數
(素數的倍數不是素數)
枚舉素數表什么時候停?枚舉到i的最小質因子,標記完就可以停了,保證每個數只被他的最小質因子篩掉
所以此時你枚舉素數P,有兩種情況:
- p和i互質
- p是i的最小質因子(用完之后i就要換新了)
可以證明每個合數都有機會被自己的最小質因子篩去
對於當前枚舉的i ,素數prime[j] ,以及標記的合數k=i*j,記下k的最小質因子
然后我們判斷這個素數prime[j]是不是i的最小質因子,如果不是,就繼續枚舉素數prime[j]否則就可以停了,去枚舉下一個i,因為你再枚舉素數並且標記也沒用了,因為后面的數還會被自己的最小質因子給標記掉
PS:假設你就是不聽話,繼續枚舉素數,假設得到prime[k],那么下一步你就會標記i*prime[k]為合數,然鵝我們剛剛得到prime[i]是i的最小質因子,那么就說明i分解后一定有prime[j],那么:
新合數yy=i*prime[k]=prime[j]*(i/prime[j])*prime[k]=prime[j]*( i/prime[j] * prime[k] )
( i/prime[j] * prime[k] )這個東西一定比i大,那么就說明后面枚舉到( i/prime[j] * prime[k] )的時候,yy還會被prime[j]標記一遍,被最小質因子標記,那么之前的標記就是無用功啊!
下面是各種版本的線性篩:
lyd版本:
e[ i ] 記錄 i 的最小質因子