FZU 1649 Prime number or not (大素数测试)

题目链接

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 ;
}

但用于这题的判断还是超时了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值