1. 程式人生 > >快速冪運算應用

快速冪運算應用

先來一個什麼是快速冪運算的講解部落格網址點選開啟連結,別人寫的

然後理解了什麼是快速冪運算後這裡要寫的就是它的一個應用,包含了埃氏篩法算區間素數的方法

題目:Carmichael Numbers (UVa No.10006)

大致意思是:我們把對任意的1<x<n都有xn≡x(mod n)成立的合數n稱為Carmichael Numbers。對於給定的整數n,請判斷它是不是Carmichael Numbers。(批註:a和b除以m後所得的餘數相等記作a≡b(mod m))

限制條件 2<n<65000

樣例:

輸入:      輸入:       輸入:        輸入:         輸入:         輸入:

17            561           4                 1729           1109           431

輸出:      輸出:       輸出:        輸出:         輸出:         輸出:

NO           YES           NO             YES             NO              NO

import java.util.Scanner;
/*不利用語言特性任何語言都可以寫*/
public class Main {
    public static boolean[] is_prime = new boolean[65001];

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        long n = cin.nextLong();
        cin.close();
        boolean flag = true;
        sieve(n); // 記錄n以內,哪些是素數
        if (is_prime[(int) n]) { // 是素數就不合題意
            flag = false;
        } else {
            for (int i = 2; i < n; ++i) { // 1<x<n都有xn≡x(mod n)成立,即從1~n的x都有xn mod n恆等於x mod n,滿足就是YES否則NO
                if (mod_pow(i, n, n) != i % n) {
                    flag = false;
                    break;
                }
            }
        }
        if (flag) {
            System.out.println("YES");
        } else {
            System.out.println("NO");
        }
    }
/*埃氏篩法原理:先將2到n範圍內的所有整數寫下來。其中最小的數字2是素數。將表中所有2的倍數都劃去。
表中剩餘的最小數字是3,它不能被更小的數整除,所以是素數。再將表中所有3的倍數都劃去。
依次類推,如果表中剩餘的最小數字是m時,m就是素數。然後將表中的所有m的倍數都劃去。像這樣反覆操作,就能依次列舉n以內的素數*/
    public static void sieve(long n) { // 埃氏篩法複雜度O(nlognlogn)看作線性也可以
        is_prime[0] = is_prime[1] = false;
        for (int i = 2; i <= n; ++i) {
            is_prime[i] = true;
        }
        for (int i = 2; i <= n; ++i) {
            if (is_prime[i]) {
                for (int j = i << 1; j <= n; j += i) {
                    is_prime[j] = false;
                }
            }
        }
    }

    public static long mod_pow(long x, long n, long mod) { // java的long是64位,c++的long long是64位,long是32位
        long res = 1;
        while (n > 0) {
            if ((n & 1) == 1) {
                res = res * x % mod;
            }
            x = x * x % mod;
            n >>= 1;
        }
        return res;
    }
}

接下來如果使用java語言特性用BigInteger的話很方便,但可能超時

import java.math.BigInteger;
import java.util.Scanner;

public class Main {
    public static boolean[] is_prime = new boolean[65001];

    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int n = cin.nextInt();
        cin.close();
        boolean flag = true;
        sieve(n);
        if (is_prime[n]) {
            flag = false;
        } else {
            for (int i = 2; i < n; ++i) {
                BigInteger ii = new BigInteger(i + "");
                if (ii.pow(n).mod(new BigInteger(n + "")).intValue() != i % n) {
                    flag = false;
                    break;
                }
            }
        }
        if (flag) {
            System.out.println("YES");
        } else {
            System.out.println("NO");
        }
    }

    public static void sieve(long n) {
        is_prime[0] = is_prime[1] = false;
        for (int i = 2; i <= n; ++i) {
            is_prime[i] = true;
        }
        for (int i = 2; i <= n; ++i) {
            if (is_prime[i]) {
                for (int j = i << 1; j <= n; j += i) {
                    is_prime[j] = false;
                }
            }
        }
    }
}
========================================Talk is cheap, show me the code=======================================