zoj 3758 Singles' Day

题目链接: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
#include
#include
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

你可能感兴趣的:(Math,Theory)