超級pow(a^b,b由數組表示)Super Pow

問題:算法

Your task is to calculate a^b mod 1337 where a is a positive integer and b is an extremely large positive integer given in the form of an array.數組

Example1:函數

a = 2
b = [3]
Result: 8

Example2:spa

a = 2
b = [1,0]
Result: 1024

解決:orm

① 暴力破解。當數組b超過必定的範圍以後Math.pow(a,b)會超出整數的範圍,致使以後結果都變爲0,因此,只能找更好的方法。rem

② 因爲任意一個數都是2的次冪的和。因此,與Pow(x, n)的處理方法相似,都要對其對半縮小,但要注意每次都要對1337取餘。注意,因爲給定的指數b是一個一維數組的表示方法,咱們要是折半縮小處理起來確定十分不方便,因此咱們採用按位來處理,好比2^23 = (2^2)^10 * 2^3, 因此咱們能夠從b的最高位開始,算出個結果存入res,而後到下一位是,res的十次方再乘以a的該位次方再對1337取餘。it

理論支持(轉冪算法):io

       (a^b) mod c = ((a mod c)^b) mod c ----公式1ast

       (x*y) mod c = ((x mod c) * (y mod c)) mod c  : 積的取餘等於取餘的積的取餘。 -----公式2form

class Solution {//9ms
    public int superPow(int a, int[] b) {
        int res = 1;
        for (int i = 0;i < b.length;i ++){
            res = (pow(res,10) * pow(a,b[i])) % 1337;
        }
        return res;
    }
    public int pow(int x,int n){
        if (n == 0) return 1;
        if (n == 1) return x % 1337;
        return (pow(x,n / 2) * pow(x,n - n /2)) % 1337;
    }
}

② 快速冪算法:

class Solution {//601ms
    public int superPow(int a, int[] b) {
        if (b.length == 0 || isZero(b)){
            return 1;
        }
        a = a % 1337;
        boolean flag = false;//標記次冪是否爲奇數
        if (b[b.length - 1] % 2 == 1){
            flag = true;//次冪是奇數
        }
        div(b,2);
        int res = superPow(a,b);
        res = (res * res) % 1337;
        if (flag){
            res = (res * a) % 1337;
        }
        return res;
    }
    public boolean isZero(int[] num){//判斷數組組成的整數是否爲0
        for (int i = num.length - 1;i >= 0;i --){
            if (num[i] > 0){
                return false;
            }
        }
        return true;
    }
    public void div(int[] x,int y){//將次冪折半
        int tmp = 0;
        for (int i = 0;i < x.length;i ++){
            x[i] += tmp * 10;
            tmp = x[i] % y;
            x[i] = x[i] / y;
        }
    }
}

③ 快速冪算法+歐拉函數

除了1及其自己,1137只能被7和191整除,a^b有以下規律:

(1)首先,若是a有除數7和191,那麼a % 1337 == 0,答案是0。

(2)若是a既沒有除數7也沒有191,那麼a和1337是互質的,因此有 a^b%c = a^(b%phi(c))%c

即a ^ b % 1337 = a ^ (b % phi(1337)) % 1337 = a^(b % 1140) % 1337。

(3)最後,一個可能有7或191的除數,這是類似的。

【注】對正整數n歐拉函數{\displaystyle \varphi (n)}\varphi (n)是小於或等於n的正整數中與n互質的數的數目。

(1)   p^k型歐拉函數:

若N是質數p(即N=p), φ(n)= φ(p)=p-p^(k-1)=p-1。

若N是質數p的k次冪(即N=p^k),φ(n)=p^k-p^(k-1)=(p-1)p^(k-1)。

(2)mn型歐拉函數

設n爲正整數,以φ(n)表示不超過n且與n互素的正整數的個數,稱爲n的歐拉函數值。若m,n互質,φ(mn)=(m-1)(n-1)=φ(m)φ(n)。

(3)特殊性質:

若n爲奇數時,φ(2n)=φ(n)。

對於任何兩個互質 的正整數a,n(n>2)有:a^φ(n)=1 mod n (恆等於)此公式即 歐拉定理

當n=p 且 a與素數p互質(即:gcd(a,p)=1)則上式有: a^(p-1)=1 mod n (恆等於)此公式即 費馬小定理

class Solution { //2ms
    public int superPow(int a, int[] b) {
        int c = 1337;
        int phi = euler(c);//1140
        int n = 0;
        for (int i = 0;i < b.length;i ++){
            n = n * 10 + b[i];
            n %= phi;
        }
        return fastPow(a,n,c);
    }
    public int fastPow(int a,int b,int c){
        a %= c;
        int res = 1;
        while(b != 0){
            if ((b & 1) != 0) res = res * a % c;//奇數
            a = a * a % c;
            b >>= 1;//除2
        }
        return res;
    }
    public int euler(int n){         int res = n;         for (int i = 2;i * i <= n;i ++){             if (n % i == 0){                 res = res / i * (i - 1);                 while(n % i == 0){                     n /= i;                 }             }         }         if (n > 1){             res = res / n * (n - 1);         }         return res;     }

相關文章
相關標籤/搜索