Problem 1649 Prime number or not
Accept: 661 Submit: 3016
Time Limit: 2000 mSec Memory Limit : 32768 KB
Problem Description
Your task is simple.
Give you a number N, you should judge whether N is a prime number or not.
Input
There are multiple test cases. For each test case, there is an integer N(2<=N<=10^18).
Output
For each test case, you should output whether N is a prime number or not.
If N is a prime number , you should output "It is a prime number."; otherwise you should output "It is not a prime number.";
Sample Input
2 4
Sample Output
It is a prime number.
It is not a prime number.
素数的判断
1、可以暴力枚举2……n的数字,如果存在某个数i,有n%i==0,那么这个数肯定不是素数,复杂度显然是O(n)。
2、稍微优化以下,可以知道实际上n的因子是成对出现的(除非N是完全平方数)。所以只需要枚举1……sqrt(N)判断即可,复杂度O(sqrt(N))。
3、可是如果N很大,那如何判断?于是基于费马定理有一种方案可以解决,即随机化算法。
我们知道对于某个素数p,由费马定理得:a^p mod p=a。
但a^p mod p=a 不是“p是素数的充分条件”,存在有名但是极其稀少的Carmichael数,它们不是素数但是满足费马小定理,比如561,1105,1729,2465,2821,6601,8911,10585,15841,29341……。所以如果我们只是随机的从1到p-1之间(这里p是一个待判断的正整数)取一个数a计算a^p mod p的值,如果它不是a,那么我们100%肯定p不是素数。但如果a^p mod p的值是a,p可能是素数也可能不是。
我们看费马小定理的一个特殊情况,如果n是一个素数,那么ψ(n)=n-1,而任意数字不大于n的数a都与n互质,于是费马小定理的推论为:当n为素数,而a为任意整数时,a^(n-1) ≡1 (mod n)。
即一个数字n为素数的必要条件是对于任意a<n,都有(a^(n-1)) mod n =1.但是这是必要条件,根据计算,如果n为任意数字,又如果单独取一个a<n,当(a^(n-1)) mod n =1成立时,有25%可能性n为合数。所以我们可以通过多次随机选择不同的a,如果上面测试都被通过,我们就可以说n有很大可能是素数。这种算法是米勒-拉宾素数测试。
以上参考自https://wenku.baidu.com/view/6cb4a2f5f90f76c661371a62.html?from=search
注意在计算a^(n-1)mod n的时候,n可能很大,所以a^(n-1)可能越界,就需要用快速幂取模,但a很大的时候a*a也可能越界,就需要用快速乘法(基于快速幂)
快速乘法可参考https://www.cnblogs.com/Howe-Young/p/4342847.html
生成随机数可参考https://www.cnblogs.com/VVingerfly/p/5990714.html
AC代码:
#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<iomanip>
#include<vector>
#include<cmath>
#include<ctime>
#include<stack>
using namespace std;
#define ll long long
#define random(a,b) (rand()%(b-a+1)+a) //取得在[a,b]间的随机数
ll fast_multi(ll a,ll b,ll m)//快速乘法
{
ll ans=0;//注意初始化是0,不是1
while(b)
{
if(b&1) ans=(ans+a)%m;
a=2*a%m;
b>>=1;
}
return ans;
}
ll mod_pow(ll a,ll b,ll m)//快速幂
{
ll ans=1;
while(b)
{
if(b&1) ans=fast_multi(ans,a,m);
a=fast_multi(a,a,m);
b>>=1;
}
return ans;
}
bool isprime(ll n)//miller rabin
{
if(n==2) return 1;
if(n<2||!(n&1)) return 0;//偶数不会是素数
srand((unsigned)time(NULL));
for(int i=1;i<=20;i++)
{
ll a=random(1,n-1);//取得在[1,n-1]的随机数
if(mod_pow(a,n-1,n)!=1) return 0;
}
return 1;
}
int main()
{
ll num;
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
while(cin>>num)
{
if(isprime(num))
cout<<"It is a prime number."<<endl;
else cout<<"It is not a prime number."<<endl;
}
}
附上一篇:判断一个数是否为质数/素数——从普通判断算法到高效判断算法思路
其中介绍了相比上述前两种更高效的算法
bool isPrime_3( int num )
{
//两个较小数另外处理
if(num ==2|| num==3 )
return 1 ;
//不在6的倍数两侧的一定不是质数
if(num %6!= 1&&num %6!= 5)
return 0 ;
int tmp =sqrt( num);
//在6的倍数两侧的也可能不是质数
for(int i= 5;i <=tmp; i+=6 )
if(num %i== 0||num %(i+ 2)==0 )
return 0 ;
//排除所有,剩余的是质数
return 1 ;
}
但用于这题的判断还是超时了。