HDU-2138-How many prime numbers(Miller-Rabin新解法)

题目传送门

sol1:普通判到sqrt(n)的素数判定,不多说了。

  • 素数判定
    #include "bits/stdc++.h"
    using namespace std;
    bool is_prime(int n) {
        for (int i = 2; 1LL * i * i <= n; i++)
        {
            if (n % i == 0) return false;
        }
        return true;
    }
    int main() {
        int n, m;
        while (~scanf("%d", &n)) {
            int cnt = 0; 
            for (int i = 1; i <= n; i++) {
                scanf("%d", &m);
                if (is_prime(m)) cnt++;
            }
            printf("%d\n", cnt);
        }
        return 0;
    }

    复杂度sqrt(m),判断n次就是n * sqrt(m);

sol2:新get到的技巧Miller-Rabin素数测试,结合了费马小定理和二次探测定理,可以更高效的判断素数,存在误判可能,不过误判可能非常小,可以忽略不计;

  • Miller-Rabin素数测试
    #include "bits/stdc++.h"
    using namespace std;
    int quick_pow(int n, int k, int p) {
        int ans = 1;
        while (k) {
            if (k & 1) ans = 1LL * ans * n % p;
            n = 1LL * n * n % p;
            k >>= 1;
        }
        return ans;
    }
    bool is_prime(int n) {
    //    if (n < 2) return false;
        int s = 0, t = n - 1;
        while (!(t & 1)) s++, t >>= 1;
        for (int i = 1; i <= 5; i++) {
            int a = rand() % (n - 1) + 1;
            int k = quick_pow(a, t, n);
            for (int j = 1; j <= s; j++) {
                int x = 1LL * k * k % n;
                if (x == 1 && k != 1 && k != n - 1) return false;
                k = x;
            }
            if (k != 1) return false;
        }
        return true;
    }
    int main() {
        int n, m;
        srand(time(NULL));
        while (~scanf("%d", &n)) {
            int cnt = 0;
            for (int i = 1; i <= n; i++) {
                scanf("%d", &m);
                if (is_prime(m)) cnt++;
            }
            printf("%d\n", cnt);
        }
        return 0;
    }

    复杂度logm,判断n次就是n * log(m);

附加一个用于 LL 范围素数测试的模板:s

  • Miller-Rabin素数测试 LL 范围模板
    typedef long long LL;
    LL quick_mul(LL n, LL k, LL p) {
        LL ans = 0;
        while (k) {
            if (k & 1) ans = (ans + n) % p;
            n = (n + n) % p;
            k >>= 1;
        }
        return ans;
    }
    LL quick_pow(LL n, LL k, LL p) {
        LL ans = 1;
        while (k) {
            if (k & 1) ans = quick_mul(ans, n, p);
            n = quick_mul(n, n, p);
            k >>= 1;
        }
        return ans;
    }
    bool is_prime(LL n) {
        if (n < 2) return false;
        LL s = 0, t = n - 1;
        while (!(t & 1)) s++, t >>= 1;
        for (int i = 1; i <= 5; i++) {
            LL a = rand() % (n - 1) + 1;
            LL k = quick_pow(a, t, n);
            for (int j = 1; j <= s; j++) {
                LL x = quick_mul(k, k, n);
                if (x == 1 && k != 1 && k != n - 1) return false;
                k = x;
            }
            if (k != 1) return false;
        }
        return true;
    }

    大致差不多,为了防止爆 LL 加了一个快速积用于乘, 所以复杂度变成了log(m) * log(m)

 

posted @ 2019-09-26 10:13  Angel&Demon  阅读(...)  评论(... 编辑 收藏