高速電力バイナリ累乗(フラット法として知られているバイナリ累乗が、)、Ο(LOGN)の一つである 時間で算出された ヒント、および計算暴力はO(N)必要 時間。
それは、法律のいずれかの操作に連動して適用することができますので、この技術は、多くの場合、非シーンの計算に使用されています。明らかにそれは、このようなマトリックス電力動作の意味として、べき乗剰余演算に適用することが可能である、私たちは次について説明します。
迅速なパワーを達成するための一般的な再帰的な方法
長い 長い binpow(長い 長い、長い 長いB){ もし、(B == 0)リターン 1 。 長い 長い RES = binpow(B / 2 )。 もし(Bの%2 ) リターン * RES * RES 。 それ以外の 戻り解像度* RES。 }
非再帰的なメソッドの実装
長い 長い binpow(長い 長い、長い 長いB){ 長い 長い RES = 1 。 一方、(B> 0 ){ 場合(B&1)RES = RES * 。= * ; B >> = 1 。 } 戻りRES。 }
質問1:迅速なパワー剰余
乗算剰余演算に影響を与えず、以下のコードので、
長い 長い binpow(長い 長い、長い 長い B、長い 長M){ A%= M。 長い 長い RES = 1 。 一方、(B> 0 ){ 場合(B&1)RES = RES *%のM。*%の= M。 B >> = 1 。 } 戻りRES。 }
注:フェルマーの小定理、mがあれば 素数である、我々はXを計算することができN-%を(1-M。)アルゴリズムのプロセスを加速します。
質問2:高速電力行列
テンプレート
構造体マット { LL M [ 101 ] [ 101 ]; }; // メモリ構造 マットA、E; // Aがマトリックス入力され、Eは出力行列である ムル(マットX、Y MAT)加算器マット { マットC。 用(INT I = 1 ; I <= N ++ {I)の ための(INT J = 1。 ; J <= N-; ++ J){ CM&LT [I] [J] = 0 ; } } のための(int型 I = 1 ++; I <= N- I){ ため(INTJ = 1 ; J <= N; ++ J){ ための(int型のk = 1 ; K <= N; ++ K){ CM [I] [J] =センチ[I] [J]%MOD + XM [I] [K] * YM [K] [J]%のMOD。 } } } 戻りC。 } マットPOW(マットLLのY、X)// 矩阵快速幂 { マットANS = E。 一方、(Y){ 場合(Y&1)ANS = ムル(ANS、X)。 X = ムル(X、X)。 Y >> = 1 。 } 戻り値は、ANS; }
1. フィボナッチ数
数のフィボナッチ再発は、行列乗算の形で表すことができます。
我々は、中O(LOGN)行列の乗算をすることができますので、時間のフィボナッチ数で計算されます。さらに、前者は式は、マトリックス技術の対角化することにより得ることができる記述する。
2. 固定長経路計算
有向グラフ(の右側)に、任意の2つのU、V見つける Uの間の Vに 、長さk個の パスの数。
我々図kの隣接行列M -乗、次にMののIJ はIから表しJのにkの長さであるパスの数。アルゴリズムの複雑さはO(N-である。3 logK)。
3 。動作点セットのジオメトリを加速
座標上でこれらの3つの操作の影響で見てみましょう:
- シフト動作:各次元座標プラス定数。
- スケール操作:各次元の座標が一定と乗算されます。
- 回し操作:これは少し複雑になり、私たちは掘り下げるつもりはないが、我々はまだ新しい座標を表現する線形結合を使用することができます。
従って、変換は4×4であってもよいし、座標上線形演算として表すことができる各変換、見ることができる :で表される行列
今、各操作をマトリックス変換配列について表されている製品のマトリックスを表すために使用することができ、そしてk番目の電力ループ動作の対応は、マトリックスを取ります。
そのようなを使用することができる 、最終的に形成されたO(MLOG(K))の変換行列全体のシーケンスを計算します。最後には、nに適用される点、O(M + MLOGの総複雑さ (K)) 。
質問3:高精度かつ高速なパワー
题目:从文件中输入 P(1000<P<3100000),计算 的最后 100 位数字(用十进制高精度数表示),不足 100 位时高位补 0。
#include <bits/stdc++.h> using namespace std; int a[505], b[505], t[505], i, j; int mult(int x[], int y[]) // 高精度乘法 { memset(t, 0, sizeof(t)); for (i = 1; i <= x[0]; i++) { for (j = 1; j <= y[0]; j++) { if (i + j - 1 > 100) continue; t[i + j - 1] += x[i] * y[j]; t[i + j] += t[i + j - 1] / 10; t[i + j - 1] %= 10; t[0] = i + j; } } memcpy(b, t, sizeof(b)); } void ksm(int p) // 快速幂 { if (p == 1) { memcpy(b, a, sizeof(b)); return; } ksm(p / 2); mult(b, b); if (p % 2 == 1) mult(b, a); } int main() { int p; scanf("%d", &p); a[0] = 1; a[1] = 2; b[0] = 1; b[1] = 1; ksm(p); for (i = 100; i >= 1; i--) { if (i == 1) { printf("%d\n", b[i] - 1); } else printf("%d", b[i]); } }
模意义下大整数乘法
也就是快速乘,思路如下
注意:也可以利用双精度浮点数在常数时间内计算大整数乘法。因为
快速乘代码实现
ll mul(ll a,ll b,ll p) { ll ans=0; for(;b;b>>=1) { if(b&1) ans=(ans+a)%p; a=a*2%p; } return ans; }
双精度代码实现
ll mul(ll a,ll b,ll p) { a%=p; b%=p; ll c=(long double)a*b/p; ll ans=a*b-c*p; if(ans<0) ans+=p; else if(ans>=p) ans-=p; return ans; }