学了这么久复习一下。
给你一堆很大的数字,怎么判断它们是不是质数?
真鸡儿简单,试除法啊!
如果数字很大的话,显然根号的试除法也能试到宇宙的尽头...所以我们要学新算法。
费马小定理:
首先是费马小定理.假如是一个整数,是一个质数,那么是p的倍数,可以表示为 (mod p),如果a不是p的倍数,这个定理也可以写成 1 (mod p)
Wiki上的这个证明很给力
那么现在我们有如果p是素数,那么一定满足 1 (mod p)。但是如果反过来呢?如果 1 (mod p),那么p是否一定是一个质数呢?答案是否定的。有一类数叫卡迈克尔数,这类数都是合数,561是最小的卡迈克尔数,假设与561互质,则被561除都余1。
所以,如果对于一个p,有(a,p)=1,且 1 (mod p),我们就只能说p是有一定概率是一个素数。那么我们要怎么样来减小判断失误的概率呢?为了解决这个问题,我们又引入了二阶检测定理。
二阶检测定理:
如果对于素数p,0<x<p,(mod p)的解为x=1orx=p-1。(证明trivial)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<stack>
#include<string>
#include<algorithm>
typedef unsigned long long ll;
using namespace std;
ll mulmod(ll a,ll b,ll mod){
ll ans=0;
while(b){
if(b&1) ans=(ans+a)%mod;
b>>=1;
a=(a*2)%mod;
}
return ans;
}
ll fastpowmod(ll a,ll b,ll mod){
ll ans=1;
while(b){
if(b&1) ans=mulmod(a,ans,mod);
b>>=1;
a=mulmod(a,a,mod);
}
return ans;
}
bool miller_rabin(ll a,ll n){
if(n==2||n==a) return true;
if(!(n&1)) return false;
ll s=n-1;
while(!(s&1)) s>>=1;
ll now = fastpowmod(a,s,n);
if(now==1||now==n-1) return true;
while(s<n-1){
s<<=1;
now=fastpowmod(now,2,n);
if(now==n-1) return true;
}
return false;
}
bool isprimer(ll n){
ll a[]={2,3,5,7,11,13,41,67};
for(int i=0;i<6;i++){
if(miller_rabin(a[i],n)==false){
return false;
}
}
return true;
}
int main(){
ll n;
while(cin>>n){
cout<<isprimer(n)<<endl;
}
return 0;
}