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