素数的判断
素数的判断:
素数的判断主要有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; }