この質問は、実際には高速パワーを調査することです。いわゆる高速パワーは、実際には高速パワーのモジュロの略です。つまり、パワー(モジュロ)のパワーをすばやく見つけることです。プログラム設計の過程で、特定の数に対して大きな数の残りを見つけることが必要になる場合が多く、より大きな計算範囲でより高速なアルゴリズムを取得するために、高速のべき係数アルゴリズムが生成されます。
簡単な例から始めましょう。
アルゴリズム1. 最初に、このアルゴリズムを直接設計します。
int ans = 1;
for(int i = 1;i<=b;i++)
{
ans = ans * a;
}
ans = ans % c;
で具現化アルゴリズムの時間複雑さのためのループであり、 O (B )。このアルゴリズム明白な問題、場合とbが大きすぎると、缶容易オーバーフロー。
それでは、最初の改善計画を見てみましょう。この計画について話す前に、まず次のような公式が必要です。
誰もが離散数学や数論でこの公式を学んだはずです。
だから、考えずに改善されました:
アルゴリズム2 :
int ans = 1;
a = a % c; //加上这一句
for(int i = 1;i<=b;i++)
{
ans = ans * a;
}
ans = ans % c;
スマートリーダーは、係数が乗算されてから乗算され、残りが変更されないため、新しく計算されたans も残りとして使用できるため、より優れた改良バージョンが得られると考えることができるはずです。
アルゴリズム3 :
int ans = 1;
a = a % c; //加上这一句
for(int i = 1;i<=b;i++)
{
ans = (ans * a) % c;//这里再取了一次余
}
ans = ans % c;
このアルゴリズムは時間の複雑さを改善していませんが、それでもO(b)ですが、はるかに優れていますが、cが大きすぎる場合でもタイムアウトする可能性があるため、次の高速電力アルゴリズムを導入します。
高速電力アルゴリズムは、以下の明白な公式に依存していますが、これは証明しません。上記の2つの式から、次の結論を導き出すことができます。
その後、次のアルゴリズムを取得できます。
アルゴリズム4 :
int ans = 1;
a = a % c;
if(b%2==1)
ans = (ans * a) mod c; //如果是奇数,要多求一步,可以提前算到ans中
k = (a*a) % c; //我们取a2而不是a
for(int i = 1;i<=b/2;i++)
{
ans = (ans * k) % c;
}
ans = ans % c;
時間の複雑さをO(b / 2)に変更したことがわかりますが、もちろんこれで症状が治るわけではありません。しかし、我々は我々が聞かせたときにことを確認することができ、K =(*)MOD Cを、状態が変化した、私たちが求めている最終的な結果がある MOD C の代わりに、元 のmod C 、我々は、このプロセスがあることを見つけます繰り返す。もちろん、奇数に対してもう1つa mod cがあるので、反復を完了するために、b が奇数の場合、 ans =(ans * a)%c によって余分な1つを補います。その一部を繰り返すことができます。
上記の反復の後、b = 0の場合、すべての因子が乗算され、アルゴリズムは終了します。その後、 O (log b )時間で完了することができます。それで、最終的なアルゴリズムがあります:高速電力アルゴリズムです。
アルゴリズム5 :高速電力アルゴリズム
int ans = 1;
a = a % c;
while(b>0)
{
if(b % 2 == 1)
ans = (ans * a) % c;
b = b/2;
a = (a * a) % c;
}
上記のアイデアはhttp://www.doc88.com/p-5836182437827.htmlから転送されます 以下は、このアイデアに従って実装したプログラム(C ++)です。
class Solution {
public:
bool notZero(vector<int>& b) {
for(int i = b.size()-1; i >= 0; i--) {
if(b[i] > 0) return true;
}
return false;
}
void div(vector<int>& b) {
int tmp = 0;
for(int i = 0; i < b.size(); i++) {
b[i] += tmp*10;
tmp = b[i] % 2;
b[i] = b[i] / 2;
}
}
int superPow(int a, vector<int>& b) {
int ans = 1;
a = a % 1337;
while(notZero(b)) {
if(b[b.size()-1] % 2 != 0) ans = (ans * a) % 1337;
div(b);
a = (a * a) % 1337;
}
return ans;
}
};