个人不是很理解Miller-Rabin算法的正确性,所以这篇东西可以图一乐(
确定性判素性的方法都很慢,所以要考虑随机但是错误概率低的判素方法。
首先有Fermat素性测试,即费马小定理的逆用。众所周知费马小定理有\(a^{m-1}\bmod m=1\),当\(m\)是质数是对\(a\in[1,m-1]\)成立。于是当要判定一个\(m\)是否是质数时,我们随机取出若干个\(a\),计算这个值是不是\(1\),若不是则可确定\(m\)不是质数,否则在一定的轮数过后可以认为\(m\)是质数。
除了不是质数却满足费马小定理的数以外,每个数都有可能被筛查出来。如果所有数都有概率被筛查出来,那么增加轮数后这个算法就具有实际意义。但是实际上仍然有不是质数却满足费马小定理的数,因此这个方法不能用于实战。
接下来介绍二次探测定理,即对于奇素数\(n\),使得\(x^2\bmod n=1\)的\(x\)有且仅有\(x=1\)与\(x=n-1\),移项后平方差即可证明。
考虑在费马小定理的判断中加入二次探测定理。即先将\(n-1\)分解为\(a\times 2^b\),然后随机\(p\)计算出\(p^a\bmod n\),然后每次平方\(p\),操作\(b-1\)次,如果结束时\(b\)不为\(n-1\)或\(1\),则代表发现新的平方根,\(n\)不为素数。
听说操作\(k\)次的正确率是\(4^{-k}\),不知道对不对。
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=4e5+5,M=N*4+5,K=1e5+5,mod=998244353,Mod=mod-1;const ll INF=2e18+7;const db eps=1e-5;mt19937 rnd(time(0));
ll x;
ll mpow(ll x,ll p,ll y){ll Ans=1;while(y) y&1&&(Ans=(__int128)Ans*x%p),y>>=1,x=(__int128)x*x%p;return Ans;}
int CK(ll n){
if(n<3||n%2==0) return n==2;ll a=n-1,b=0;while(a%2==0) a/=2,b++;
int t=8,i;while(t--){
ll x=R(n-2)+2,p=mpow(x,n,a);
if(p==1) continue;
for(i=0;i<b;i++){
if(p==n-1) break;p=(__int128)p*p%n;
}if(i>=b) return 0;
}return 1;
}
int main(){
freopen("1.in","r",stdin);
int i,j;while(~scanf("%lld",&x)) puts(CK(x)?"Y":"N");
}
标签:int,Miller,质数,算法,定理,using,Rabin,ll,define
From: https://www.cnblogs.com/275307894a/p/17037623.html