hdu 1905 poj3641素数判定与快速幂取余

还是比较简单的,看题目的数据范围,貌似简单判断素数的方法(复杂度sqrt(p))也能过,不过手上有素数测试的模板,就直接用了。秒杀。。。

/*
 * hdu1905/win.cpp
 * Created on: 2012-7-12
 * Author    : ben
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <functional>
#include <numeric>
#include <cctype>
using namespace std;

typedef long long LL;

int modular_exp(int a, int b, int c) {
    LL res, temp;
    res = 1 % c, temp = a % c;
    while (b) {
        if (b & 1) {
            res = res * temp % c;
        }
        temp = temp * temp % c;
        b >>= 1;
    }
    return (int) res;
}

int witness(int a, int n) {
    LL x, d = 1,i = (LL)(ceil(log(n - 1.0) / log(2.0)) - 1);
    for (; i >= 0; i--) {
        x = d;
        d = (d * d) % n;
        if (d == 1 && x != 1 && x != n - 1)
            return 1;
        if (((n - 1) & (1 << i)) > 0)
            d = (d * a) % n;
    }
    return (d == 1 ? 0 : 1);
}

int miller_rabin(int n, int s = 50) {
    if (n == 2)
        return 1;
    if ((n % 2) == 0)
        return 0;
    int j;
    LL a;
    for (j = 0; j < s; j++) {
        // rand()随机产生[0, RAND_MAX)内的整数RAND_MAX=32768
        // 直接%n产生不了[RAND_MAX, n)之间的数,使用LL防止乘法溢出
        a = (LL)rand() * (n - 2) / RAND_MAX + 1;
        if (witness(a, n))
            return 0;
    }
    return 1;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("data.in", "r", stdin);
#endif
    int p, a;
    while(scanf("%d%d", &p, &a) == 2) {
        if(p == 0 && a == 0) {
            break;
        }
        if(miller_rabin(p)) {
            puts("no");
            continue;
        }
        if(modular_exp(a, p, p) == a) {
            puts("yes");
        }else {
            puts("no");
        }
    }
    return 0;
}
posted @ 2012-07-12 13:32  moonbay  阅读(213)  评论(0编辑  收藏  举报