素数的判断:
素数的判断主要有2种方法:1.试除法 2.Miller_Rabbin随机化算法
一、试除法:
(1)朴素的试除法:
对于一个数N,我们可以从让其被除遍1~N,如果有一个数可以除尽N,则其为合数,如果都不能将其除尽,则其为质数;
时间复杂度O(N)
优化:
(2)将N从1除到sqrt(N)即可:时间复杂度O(sqrt(N))
证明:对于任意的N若存在u使得N能被u整除,那么一定存在(N/u),使N可以除尽(N/u);(N/u)*u = N;
故有方程N/u = u;所以u = sqrt(N);
(3)将N除从1到sqrt(N)的质数 时间复杂度O(In(sqrt(N))) 当然他有O(N)的筛素数的时间(筛素数的方法见:留坑)
证明:对于任意一个数N,如果N可以被u除尽,而u是合数,那么他的质因子m一定可以除尽N;
而根据质数分布规律,在1~N中质数的个数接近于In(N)
故算法可行,时间复杂度为O(In(sqrt(N))+N)
如果多次询问(询问m次),时间复杂度为O(mIn(sqrt(N))+N)
而简单的试除只有O(msqrt(N));
(4) 玄学数论:如果一个数是质数,那么它取模6只能是1或5。时间复杂度O((1/3)*基础算法复杂度)(2,3特判)
证明:表示博主也不会证,只是听数竞同学说的,故证明略;
(2)Miller_Rabbin随机化算法:
原理:如果一个数N,满足a^(N-1) mod N = 1(a为质数),则他极有可能是质数,如果不满足上述性质,则他是合数;
我们可以取很多个质数,对N进行验证,如果它都符合上述质数的条件,那么我们可以认为他是质数,其正确率经过证明最大接近80%左右;
错判率还是很大,怎么办?
于是我们有第二个定理:如果一个数是质数,且N-1是偶数,那么a^((N-1) /2)mod N = 1或N-1;
我们可以不断的除下去直到判为合数或N-1被除K次后为奇数,经过计算,其正确率为99.9999%;
时间复杂度O(logN),最坏O((logN)^2)
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
long long mul(long long a , long long b , long long P)
{
long long tmp = (long double) a * b / P;
return ((a * b - tmp * P) % P + P) % P;
}
long long quick_mod(long long a,long long n,long long mod)
{
if(n == 0) return 1;
long long l = quick_mod(a,n/2,mod);
if(n % 2 == 0) return mul(l,l,mod);
else return mul(a,mul(l,l,mod),mod);
}
bool Miller_Rabbin(long long x)
{
if(x == 2 || x == 3) return true;
if(x % 6 != 5 && x % 6 != 1) return false;
int prim[9] = {2,3,5,7,11,13,17,19,23};
long long tmp;
long long tnp;
for(int i = 0 ; i < 9 ; i++)
{
if(prim[i] == x) return true;
else if(prim[i] > x) return false;
tmp = quick_mod(prim[i],x-1,x);
tnp = x - 1;
if(tmp != 1) return false;
while(tnp % 2 == 0 && tmp == 1) //?
{
tnp /= 2;
tmp = quick_mod(prim[i],tnp,x);
if(tmp != 1 && tmp != x-1) return false;
}
}
return true;
}
int main(void)
{
long long int x;
while(cin>>x)
{
if(x == EOF) break;
else if(x == 1) puts("N");
else if(Miller_Rabbin(x)) puts("Y");
else puts("N");
}
return 0;
}