要判定一个数是不是质数,最妇孺皆知的方法莫过于O(sqrt(n))的方法了(相信大家看见时间复杂度已经知道方法了……)。然而还有基于随机的算法:
首先要知道的是费马小定理:
当p是质数时,a^(p-1)≡1(mod p) (gcd(a,p)=1)
实际上呢,这条东东可以写成:a^(p-1)%p=1
不幸的是,当上面成立时,p并不一定是质数……
然而,令人欣慰的是,如果上面不成立,p一定是合数。
于是,那么每次要判断p
是否为质数,只需随机一个a
(可能是为了方便,1<a<p
),判断p
是否为合数。每次判断错误地将合数判断为质数的概率约为25%,但只要判断多几次(如20次),错判的概率就会很小很小,小到看不见了……
typedef long long ll;
bool miller_rabin (ll p)
{
if (p<=1) return 0;
if (p==2) return 1;
int s=20;
while (s--)
{
ll a=rand()%(p-2)+2;
if (!pow_mod (a,p-1,p)) return 0;
}
return 1;
}
标题都说了,是硕质数,因此可能超过int
,因此在求多次方时,要使用快速幂。
同时,快速幂中两个数相乘时,也要使用类似的分治思想,避免溢出。
ll mul (ll a,ll b,ll m) //a*b%m
{
ll ans=0;
while (b)
{
if (b&1) ans=(ans+a)%m;
a=(a+a)%m;
b>>=1;
}
return ans;
}
bool pow_mod (ll a,ll b,ll m) //a^b%m
{
ll ans=1;
while (b)
{
if (b&1) ans=mul (ans,a,m);
a=mul (a,a,m);
b>>=1;
}
if (ans!=1) return 0;
return 1;
}
O(k*log³n)
(k为判断轮数)
CC 原创文章采用CC BY-NC-SA 4.0协议进行许可,转载请注明:“转载自:Miller Rabin”