快速冪取模
用法:用於求解 a 的 b 次方,而b是一個非常大的數,用O(n)的複雜度會超時。那麼就需要這個算法,注意它不但可以對數求次冪,而且可用於矩陣快速冪。
假如求 x ^ n 次方
我們可以把 n 表示爲 2^k1 + 2^k2 + 2^k3....,可以證明所有數都可以用前式來表示。(其實就是二進制表示數的原理,k1,k2……就是二進制的每一位)
那麼 x^n = x^2^k1 * x^2^k2 * x^2^k3......
那麼就可以利用二進制來加快計算速度了。
假如 x^22 , 22轉化爲二進制爲 10110, 即 x^22 = x^16 * x^4 * x^2;
那麼是不是可以在O(logn)的複雜度求解。
代碼:
-
typedef long long LL;
-
LL fun(LL x,LL n,)
-
{
-
LL res=1;
-
while(n>0)
-
{
-
if(n & 1)
-
res=(res*x)%Max;
-
x=(x*x)%Max;
-
n >>= 1;
-
}
-
return res;
-
}
那麼假如讓你求一個矩陣的很大的次方冪呢,當然我們同樣可以求解。
比如我們都知道斐波那契數列可以用矩陣來求
當求第非常大的一個斐波那契數的後幾位時我們可以用上面方法求解了。
方法和上面的方法一模一樣,只是把數 x 變成了一個矩陣。
注意代碼中矩陣的存法,很好用,題目鏈接:http://acm.nyist.net/JudgeOnline/problem.php?pid=148
-
#include <cstdio>
-
#include <iostream>
-
#include <vector>
-
-
using namespace std;
-
typedef vector<int> vec;
-
typedef vector<vec> mat;
-
typedef long long LL;
-
const int N = 10000;
-
mat mul(mat a,mat b)
-
{
-
mat c(a.size(),vec(b[0].size()));
-
for(int i=0;i<a.size();i++)
-
{
-
for(int k=0;k<b.size();k++)
-
{
-
for(int j=0;j<b[0].size();j++)
-
c[i][j] = ( c[i][j] + a[i][k] * b[k][j] ) % N;
-
}
-
}
-
return c;
-
}
-
-
mat solve_pow(mat a,int n)
-
{
-
mat b(a.size(),vec(a.size()));
-
for(int i=0;i<a.size();i++)
-
b[i][i]=1;
-
while(n>0)
-
{
-
if(n & 1)
-
b=mul(b,a);
-
a=mul(a,a);
-
n >>= 1;
-
}
-
-
return b;
-
}
-
LL n;
-
void solve()
-
{
-
mat a(2,vec(2));
-
while(~scanf("%d",&n) && n!=-1)
-
{
-
a[0][0]=1,a[0][1]=1;
-
a[1][0]=1,a[1][1]=0;
-
a=solve_pow(a,n);
-
printf("%d\n",a[1][0]);
-
}
-
}
-
int main()
-
{
-
solve();
-
return 0;
-
}
原文:http://blog.csdn.net/y990041769/article/details/22311889