#1287 : 数论一·Miller-Rabin质数测试
-
3 3 7 9
样例输出
-
Yes Yes No
描述
小Hi和小Ho最近突然对密码学产生了兴趣,其中有个叫RSA的公钥密码算法。RSA算法的计算过程中,需要找一些很大的质数。
小Ho:要如何来找出足够大的质数呢?
小Hi:我倒是有一个想法,我们可以先随机一个特别大的初始奇数,然后检查它是不是质数,如果不是就找比它大2的数,一直重复,直到找到一个质数为止。
小Ho:这样好像可行,那我就这么办吧。
过了一会儿,小Ho拿来了一张写满数字的纸条。
小Ho:我用程序随机生成了一些初始数字,但是要求解它们是不是质数太花时间了。
小Hi:你是怎么做的啊?
说着小Hi接过了小Ho的纸条。
小Ho:比如说我要检测数字n是不是质数吧,我就从2开始枚举,一直到sqrt(n),看能否被n整除。
小Hi:那就对了。你看纸条上很多数字都是在15、16位左右,就算开方之后,也有7、8位的数字。对于这样大一个数字的循环,显然会很花费时间。
小Ho:那有什么更快速的方法么?
小Hi:当然有了,有一种叫做Miller-Rabin质数测试的算法,可以很快的判定一个大数是否是质数。
输入
第1行:1个正整数t,表示数字的个数,10≤t≤50
第2..t+1行:每行1个正整数,第i+1行表示正整数a[i],2≤a[i]≤10^18
输出
第1..t行:每行1个字符串,若a[i]为质数,第i行输出"Yes",否则输出"No"
c++ 代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
LL cheng(LL a,LL b,LL mod)
{
int ch[40]={0},ch2[40]={0};
int lp1=0,lp2,ge;
while (a)
{
ch[lp1++]=a%10;
a/=10;
}
lp2=0;
while (b)
{
ge=b%10;
for (int i=lp2;i<lp2+lp1;i++)
{
ch2[i]=ch2[i]+ch[i-lp2]*ge;
if (ch2[i]>9)
{
ch2[i+1]+=ch2[i]/10;
ch2[i]%=10;
}
}
b/=10;
lp2++;
}
LL ans=0;
for (int i=39;i>=0;i--)
{
ans=(ans*10+ch2[i])%mod;
}
return ans;
}
LL pp(LL a,LL n,LL mod)
{
LL s=1,lp=a;
while (n)
{
if (n%2)
{
s=cheng(s,lp,mod);
}
lp=cheng(lp,lp,mod);
n/=2;
}
return s;
}
bool pan(LL a,LL n)
{
if (n<2) return false;
if (n==2) return true;
if ((n&1)==0) return false;
LL u=n-1;if (u<=a) return true;
while (!(u&1)) u>>=1;
LL t=pp(a,u,n);
while ((u!=n-1)&&(t!=1)&&(t!=n-1))
{
t=cheng(t,t,n);
u<<=1;
}
return (t==n-1||(u&1)==1);
}
int main()
{
int t;scanf("%d",&t);
LL a;LL shu[25]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
while (t--)
{
bool fafe=true;
scanf("%lld",&a);
for (int i=0;i<12;i++)
{
fafe=pan(shu[i],a);
if (!fafe) break;
}
printf("%s\n",fafe?"Yes":"No");
}
return 0;
}
输入一个数N(2 <= N <= 10^30)
如果N为质数,输出"Yes",否则输出"No"。
17
Yes
java版:
import java.util.*;
import java.math.*;
public class Main{
public static BigInteger pp(int a,BigInteger n,BigInteger mo)
{
BigInteger s,lp,tw;
tw=BigInteger.valueOf(2);
s=BigInteger.ONE;
lp=BigInteger.valueOf(a);
while (n.compareTo(BigInteger.ZERO)!=0)
{
if ((n.remainder(tw)).compareTo(BigInteger.ONE)==0)
{
s=s.multiply(lp);
s=s.remainder(mo);
}
lp=lp.multiply(lp);
lp=lp.remainder(mo);
n=n.divide(tw);
}
return s;
}
public static int pan(int a,BigInteger n)
{
if (n.compareTo(BigInteger.ONE.add(BigInteger.ONE))==0) return 1;
BigInteger tw = BigInteger.ONE.add(BigInteger.ONE);
if (n.remainder(tw).compareTo(BigInteger.ZERO)==0) return 0;
BigInteger u;
u=n.subtract(BigInteger.ONE);
BigInteger aa=BigInteger.valueOf(a);
if (!(u.compareTo(aa)==1)) return 1;
while ((u.remainder(tw).compareTo(BigInteger.ZERO))==0)
u=u.divide(tw);
BigInteger t=pp(a,u,n);
while ((u.compareTo(n.subtract(BigInteger.ONE))!=0)&&(t.compareTo(BigInteger.ONE)!=0)&&(t.compareTo(n.subtract(BigInteger.ONE))!=0))
{
t=(t.multiply(t)).remainder(n);
u=u.multiply(tw);
}
if ( (t.compareTo(n.subtract(BigInteger.ONE))==0)||( (u.remainder(tw)).compareTo(BigInteger.ONE)==0 )) return 1;
return 0;
}
public static void main(String args[]){
Scanner cin = new Scanner(System.in);
BigInteger n;
int fafe;
int shu[] = new int[25];
shu[0]=2;shu[1]=3;shu[2]=5;shu[3]=7;shu[4]=11;shu[5]=13;shu[6]=17;shu[7]=19;shu[8]=23;shu[9]=29;shu[10]=31;shu[11]=37;shu[12]=41;
shu[13]=43;shu[14]=47;shu[15]=53;shu[16]=59;shu[17]=61;shu[18]=67;shu[19]=71;shu[20]=73;shu[21]=79;shu[22]=83;shu[23]=89;shu[24]=97;
n=cin.nextBigInteger();
fafe=1;
for (int i=0;i<25;i++)
{
fafe=pan(shu[i],n);
if(fafe==0)
break;
}
if (fafe==1)
System.out.println("Yes");
else
System.out.println("No");
}
}