题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5203
题目大意:给定进制b和1的个数n,求转为10进制后是不是素数。
题目分析:进制转化+Miller-Rabin随机性素数测试算法。
Miller-Rabin随机性素数测试算法:
定理:若p是素数,x是小于p的正整数,x^2 mod p = 1,则x=1或x=p-1。
证明:p mod x^2-1 = 0, p mod (x-1)(x+1) = 0, 若p mod x-1 = 0, x=1, 若p mod x+1 = 0, x=p-1。
Miller-Rabin素性测试的方法举例:
2^340 mod 341=1;
2^170 mod 341=1;
2^85 mod 341=32;
则341不为素数。
随机选取k个底数进行测试算法的失误率大概为4^(-k)。
代码参考:
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long LL;
//一般Miller_Rabin素数测试是随机选择100个a,这样的失误率为0.25^100
//但在OI&&ACM中,可以使用下面一组a,失误率0.25^10
int pri[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
LL mul(LL a, LL b, LL c) //二分法求a*b%c,a,b,c<2^63
{ //为了防止long long型a * b溢出,有时需要把乘法变加法
//且因为暴力加法会超时要使用二分快速乘法模(模仿二分快速幂模)
LL r = 0, d = a;
while(b)
{
if(b&1) r = (r+d)%c;
d <<= 1;
d %= c;
b >>= 1;
}
return r;
}
LL pmod(LL a, LL b, LL c)//二分法求a^b%c;
{
LL r = 1, d = a;
while(b)
{
if(b&1) r = mul(r, d, c);//r=r*d%c
d = mul(d, d, c);//d=d*d%c
b >>= 1;
}
return r;
}
bool miller_rabin(LL n)//miller-rabin法测试素数,素数return true.测试次数10次
{ //判断是否为素数,原理依据为欧拉定理
//若a,n互质,则a^phi(n)==1(mod n)==>a^(n-1)%n==1;再结合二次剩余定理,
//若x^2%n==1,则x=1或-1;即:如果存在x!=-1且!=-1使得x^2%n==1,则n不为素数;
if(n == 1) return false;
if(n == 2) return true;
if(!(n&1)) return false;
LL k = 0, i, j, m, a;
m = n-1;
while(m%2 == 0)//将n分解为m*2^k
{
m >>= 1;
k++;
}
for(i=0; i<10; i++)
{
if(pri[i]>= n) return 1;
a = pmod(pri[i], m, n);//a = pri[i]^m%n;
if(a == 1) continue;
for(j=0; j<k; j++)
{
if(a == n-1) break;
a = mul(a, a, n);//a=a*a%n
}
if(j<k) continue;
return false;
}
return true;
}
LL getVal(int num, int b)
{
LL r = 0;
while(num--)
{
r = (r*b)+1;
}
return r;
}
int main()
{
int t, b, num;
LL n;
while(~scanf("%d%d", &b, &num))
{
n = getVal(num, b);
puts(miller_rabin(n) ? "YES" : "NO");
}
return 0;
}