NOI数论姿势瞎总结

Miller-Rabin素数检测

费马小定理:没人不会吧。

二次探测:如果\(n\)是质数,\(x^2 \equiv 1\ (\mod n)\)的解只有\(x \equiv 1\)\(x \equiv n-1\ (\mod n)\)

实现方法:

选取一些质数。\(n\)不超过\(3 \times 10^{18}\)的时候只需要\(2 \sim 23\)\(n\)unsigned long long范围内时只需要\(2 \sim 37\)。对于每个质数:

  1. 使用费马小定理的逆否定理检测。

  2. 此时,我们有\(p^{n-1} \equiv 1\ (\mod n)\),如果不出意外\(n\)是质数的话,根据二次探测定理,\(p^{\frac{n-1}{2}},p^{\frac{n-1}{4}}...\)在模意义下都应该为\(1\),直到一次取到\(n-1\)时规律消失。

所以我们可以倒序处理,根据第一次出现\(n-1\)的位置进行探测。

代码

int mi[9]={2,3,5,7,11,13,17,19,23};

inline LL qmul(LL x,LL y,LL mod){
    LL z=(long double)x/mod*y+0.5;
    return ((x*y-z*mod)%mod+mod)%mod;
}

inline LL qpow(LL x,LL y,LL mod){
    LL ret=1,tt=x%mod;
    while(y){
        if(y&1)ret=qmul(ret,tt,mod);
        tt=qmul(tt,tt,mod);
        y>>=1;
    }
    return ret;
}

inline bool miller_rabin(LL x){
    if(x==1)return false;
    rin(i,0,8)if(x==mi[i])return true;
    rin(i,0,8)if(x%mi[i]==0)return false;
    LL a=x-1;int b=0;
    while(!(a&1))a>>=1,++b;
    rin(i,0,8){
        if(qpow(mi[i],x-1,x)!=1)return false;
        LL now=qpow(mi[i],a,x);
        if(now==1||now==x-1)continue;
        rin(j,1,b-1){
            now=qmul(now,now,x);
            if(now==x-1)break;
            if(j==b-1)return false;
        }
    }
    return true;
}

猜你喜欢

转载自www.cnblogs.com/ErkkiErkko/p/11134978.html