快速冪運算應用
阿新 • • 發佈:2019-01-27
先來一個什麼是快速冪運算的講解部落格網址點選開啟連結,別人寫的
然後理解了什麼是快速冪運算後這裡要寫的就是它的一個應用,包含了埃氏篩法算區間素數的方法
題目: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的話很方便,但可能超時
========================================Talk is cheap, show me the code=======================================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; } } } } }