Miller_Rabin素数测试

介绍

当我们需要判断一个大数是否为素数,而$O(\sqrt n)$的时间复杂度又不可接受时,就需要用到Miller_Raibin素数测试了。Miller_Rabin素数测试是一种随机算法,但是正确率可以接受。

算法流程

费马小定理测试

由费马小定理,我们知道若$p$是素数,那么对于$\forall a\in(0,p)$有$a^{p-1}\equiv 1(\mod p)$。它的逆否命题同样成立。

二次探测测试

如果$p$是素数,那么对于方程$a^2\equiv1 (\mod p)$在$a\in(0,p)$中的解只有$a=1$或$a=p-1$。它的逆否命题成立。

Miller_Rabin

假设我们现在判定$n$是否为素数。

首先排除$n<2$和$n\equiv0(\mod 2)$的情况。现在$n$是一个正奇数,那么$n-1$一定是一个正偶数。

我们可以把$n-1$写成$m*2^p$,其中$m$是正奇数,$p$是正整数。

然后选定多个底$a\in (1,p)$,进行费马小定理测试和对$(a^m)^2,(a^{2m})^2,(a^{2^2m})^2,\cdots,(a^{2^{p-1}m})^2$进行二次探测测试。

如果选定不同$a$的个数为$T$,那么Miller_Rabin出错的概率是$(\frac{1}{4})^T$。当$T$较大时就可以承受了。

参考代码

#include <bits/stdc++.h>
#define LL long long
using namespace std;

LL FastPow( LL x, LL y, LL Mod ) {
    LL Ans = 1;
    for( ; y; y >>= 1, x = ( __int128 ) x * x % Mod )
        if( y & 1 )
            Ans = ( __int128 ) Ans * x % Mod;
    return Ans;
}

bool Miller_Rabin( LL n, LL Times ) {
    if( n == 2 || n == 3 ) return true;
    if( n < 2 || n % 2 == 0 ) return false;
    LL m = n - 1, p = 0;
    while( !( m & 1 ) ) {
        m >>= 1;
        ++p;
    }
    if( n == 2 || n == 3 ) return true;
    if( n < 2 || n % 2 == 0 ) return false;
    for( LL i = 0; i < Times; ++i ) {
        LL a = rand() % ( n - 2 ) + 2;
        a = FastPow( a, m, n );
        for( LL i = 1; i <= p; ++i ) {
            LL b = a;
            a = ( __int128 ) a * a % n;
            if( a == 1 && b != 1 && b != n - 1 ) return false;
        }
        if( a != 1 ) return false;
    }
    return true;
}

int main() {
    srand( ( unsigned LL ) "应该不会卡19260817" );
    LL n;
    while( scanf( "%lld", &n ) == 1 )    
        if( Miller_Rabin( n, 8 ) ) printf( "Y\n" ); else printf( "N\n" );
    return 0;
}


  Reprint please specify: chy's blog Miller_Rabin素数测试

 Previous
Pollard_Rho Pollard_Rho
注:有参考于LinearODE的博客 引入现有一个问题:如何求一个大数的一个因子(最大、最小、任意一个),而数据范围是64位带符号整形,并且有100次询问。那么枚举显然是不现实的,我们就需要一个更加高效的算法。在学习Pollard_Rho之
2019-04-20
Next 
最小割树 最小割树
目标解决问题「CQOI2016」不同的最小割。 算法介绍最小割树用于解决一类多点之间最小割的问题。luogu上的题:【模板】最小割树(Gomory-Hu Tree)。然后我们借助这道模板题来看看如何实现。 首先我们选择两个点$x$和$y$,
2019-04-19
  TOC