Miller-Rabin算法 codevs 1702 素数判定 2
Posted tech-chen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Miller-Rabin算法 codevs 1702 素数判定 2相关的知识,希望对你有一定的参考价值。
转载自:http://www.dxmtb.com/blog/miller-rabbin/
普通的素数测试我们有O(√ n)的试除算法。事实上,我们有O(slog³n)的算法。
定理一:假如p是质数,且(a,p)=1,那么a^(p-1)≡1(mod p)。即假如p是质数,且a,p互质,那么a的(p-1)次方除以p的余数恒等于1。(费马小定理)
该定理的逆命题是不一定成立的,但是令人可喜的是大多数情况是成立的。
于是我们就得到了一个定理的直接应用,对于待验证的数p,我们不断取a∈[1,p-1]且a∈Z,验证a^(p-1) mod p是否等于1,不是则p果断不是素数,共取s次。其中a^(p-1) mod p可以通过把p-1写成二进制,由(a*b)mod c=(a mod c)*b mod c,可以在t=log(p-1)的时间内计算出解,如考虑整数相乘的复杂度,则一次计算的总复杂度为log³(p-1)。这个方法叫快速幂取模。
为了提高算法的准确性,我们又有一个可以利用的定理。
定理二:对于0<x<p,x^2 mod p =1 => x=1或p-1。
我们令p-1=(2^t)*u,即p-1为u二进制表示后面跟t个0。我们先计算出x[0]=a^u mod p ,再平方t次并在每一次模p,每一次的结果记为x[i],最后也可以计算出a^(p-1) mod p。若发现x[i]=1而x[i-1]不等于1也不等于p-1,则发现p果断不是素数。
可以证明,使用以上两个定理以后,检验s次出错的概率至多为2^(-s),所以这个算法是很可靠的。
需要注意的是,为了防止溢出(特别大的数据),a*b mod c 也应用类似快速幂取模的方法计算。当然,数据不是很大就可以免了
codevs 1702 素数判定 2
一个数,他是素数么?
设他为P满足(P<=2^63-1)
P
Yes|No
2
Yes
算法导论——数论那一节
注意Carmichael Number
分类标签 Tags 点此展开
1 /*我唯一想说的就是,这个题目数据错了*/ 2 #define S 15 3 #include<iostream> 4 using namespace std; 5 #include<cstdio> 6 #define ll long long 7 #include<cstdlib> 8 #include<ctime> 9 ll quick_mod(ll x,ll u,ll n) 10 { 11 x%=n; 12 ll ans=1; 13 while(u) 14 { 15 if(u&1) 16 { 17 u--; 18 ans=(ans*x)%n; 19 } 20 u>>=1; 21 x=(x*x)%n; 22 } 23 return ans; 24 } 25 bool miller_rabin(ll n) 26 { 27 if(n==2) return true; 28 if(n==1||!(n&1)) return false; 29 ll u=n-1; 30 ll t=0; 31 while(!(u&1)) 32 { 33 t++; 34 u>>=1; 35 } 36 for(int i=0;i<S;++i) 37 {/*这里可以随机找出x,也可以手打一张表,int ss[7]={2,3,5,7,11,13,17};事实证明这个表在long long范围内都是正确的*/ 38 ll x=rand()%(n-1)+1; 39 x=quick_mod(x,u,n); 40 for(int i=1;i<=t;++i) 41 { 42 ll y=quick_mod(x,2,n); 43 if(y==1&&x!=1&&x!=n-1) 44 return false; 45 x=y; 46 } 47 if(x!=1) 48 return false; 49 } 50 return true; 51 } 52 int main() 53 { 54 srand(time(0)); 55 ll n; 56 cin>>n; 57 if(miller_rabin(n)) 58 printf("Yes"); 59 else printf("No"); 60 return 0; 61 }
以上是关于Miller-Rabin算法 codevs 1702 素数判定 2的主要内容,如果未能解决你的问题,请参考以下文章