数论 —— 素性测试
【概述】
判斷素數是一個較常涉及的內容,所謂素性測試是檢測一個數是否為素數的測試。
素數定理:,其中 π(x) 表示不超過 x 的素數的個數
質數分布密度定理:素數的分布越來越稀疏,當 1E18 內的任意兩個素數的差不會很大(不會超過 300)
【埃拉托斯特尼篩法】
初始時,先假設所有數都是素數,從2開始枚舉,當找到一個素數時,顯然這個素數乘上另外一個數之后都是合數,把這些合數都篩掉,繼續向下枚舉,直至所有數枚舉完畢。
int primes[N],cnt; bool bprime[N]; void getPrime(int n){memset(bprime,false,sizeof(bprime));bprime[0]=true;bprime[1]=true; for(int i=2;i<=n;i++){if(!bprime[i]){prime[cnt++]=i;for(LL j=i*2;j<=n;j+=i)bprime[j]=true;}} }【線性篩法】
仔細分析埃拉托斯特尼篩法可發現,這種方法會造成重復篩除合數,影響效率。
以 30 為例,在 i=2 的時候,k=2*15 篩了一次;在i=5,k=5*6 的時候又篩了一次。
未避免冗余,提高效率,也就有了快速線性篩法,其可保證不會重復刪除一個數。
原理:
① 如果 i 是素數,那么一個大的素數 i 乘以一個不大于 i 的素數,這樣篩出的數都是:?形式的,是不會重復的。
② 如果 i 是合數,此時 i 可以表示為遞增素數相乘,即:,P1 是最小的系數。
③ 當執行到 p1=prime[j] 的時候,篩選就終止了,也即只能篩選出 不大于 p1 的素數 * i
int primes[N],cnt; bool bPrime[N]; void getPrimes(int n){memset(bPrime,false,sizeof(bPrime));for(int i=2;i<=n;i++){if(!bPrime[i])primes[cnt++]=i;for(int j=0;j<cnt&&i*primes[j]<n;j++){bPrime[i*primes[j]]=true;if(i%primes[j]==0)break;}} }【判素數】
1.試除法
當數據范圍較小的情況下,判斷素數可從判斷 2 到 sqrt(n) 或者 n/2 ,看能不能整除 n,若能整除就不是素數。
bool judge(int n){if(n==1)//為1時,不是return false;for(int i=2;i<sqrt(n);i++)//如果能被整除,不是if(n%i==0)return false;return true; }?2.篩法判斷
當數據范圍較大且需要多次查詢的情況下,判斷素數可以首先利用篩法篩出所有素數,然后再進行判斷
int primes[N],cnt; bool bPrime[N]; void getPrimes(int n){memset(bPrime,false,sizeof(bPrime));for(int i=2;i<=n;i++){if(!bPrime[i])primes[cnt++]=i;for(int j=0;j<cnt&&i*primes[j]<n;j++){bPrime[i*primes[j]]=true;if(i%primes[j]==0)break;}} } bool judge(LL x){for(int i=0;i<cnt&&(LL)primes[i]*primes[i]<=x;i++)if(x%primes[i]==0)return false;return true; }3.Miller-Rabin 算法
Miller-Rabin 算法是一個隨機算法,隨機生成幾個 a 利用費馬小定理與二次探測定理來檢測素數。
只需要多次尋找不超過 n-1 基并檢驗是否有?, 如果一直有, 那么這個數大概率就是一個素數,否則可以立即判定這個數是個合數。
雖然看似沒有問題,但卻存在一些數,對于 a 的某些選擇可以騙過該算法,這些數雖然不是素數,但卻對所有與 p 互素的 0<a<p 滿足?,因此,還需要附加二次探測定理的測試來改進不出錯的幾率。
LL Mult_Mod(LL a,LL b,LL m)//res=(a*b)%m {a%=m;b%=m;LL res=0;while(b){if(b&1)res=(res+a)%m;a=(a<<=1)%m;b>>=1;}return res%m; } LL Pow_Mod(LL a, LL b, LL m)//res=(a^b)%m {LL res=1;LL k=a;while(b){if((b&1))res=Mult_Mod(res,k,m)%m;k=Mult_Mod(k,k,m)%m;b>>=1;}return res%m; } bool Witness(LL a,LL n,LL x,LL sum) {LL judge=Pow_Mod(a,x,n);if(judge==n-1||judge==1)return 1;while(sum--){judge=Mult_Mod(judge,judge,n);if(judge==n-1)return 1;}return 0; } bool Miller_Rabin(LL n) {if(n<2)return 0;if(n==2)return 1;if((n&1)==0)return 0;LL x=n-1;LL sum=0;while(x%2==0){x>>=1;sum++;}int times=20;for(LL i=1;i<=times;i++){LL a=rand()%(n-1)+1;//取與p互質的整數aif(!Witness(a,n,x,sum))//費馬小定理的隨機數檢驗return 0;}return 1; } int main() {int p;cin>>p;if(Miller_Rabin(p))cout<<p<<"可能是素數"<<endl;elsecout<<p<<"是合數"<<endl;return 0; }【例題】
總結
以上是生活随笔為你收集整理的数论 —— 素性测试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 方格取数(信息学奥赛一本通-T1277)
- 下一篇: 最短路径问题(信息学奥赛一本通-T134