一、快速幂
快速幂是一种用于快速计算出(因为太大,通常需要对一个数取模)的算法。因为较为基础,在此不多做讲解。主要原理:,,。因为指数在每次运算中都会缩小一半,时间复杂度为。代码如下。
int ksm(int a,int k,int p)
{
if(!k) return 1;
int tmp=ksm(a,k/2,p);
if(k%2) return tmp*tmp*a%p;
return tmp*tmp%p;
}
当模数较大时,三个数连乘常常会爆,所以我们最好把函数设为。不过在实际应用中,还可能出现爆的情况...因此我们需要稍作修改。代码如下。
typedef long long ll;
ll ksm(ll a,ll k,ll p)
{
if(!k) return 1;
ll tmp=ksm(a,k/2,p);
if(k%2) return tmp*tmp%p*a%p;//注意此处
return tmp*tmp%p;
}
二、矩阵快速幂
什么是矩阵快速幂呢?就是普通快速幂中的变成了一个矩阵。什么情况下会用到矩阵乘法呢?其实,数列的递推公式与矩阵乘法就有着千丝万缕的联系。举个很简单的例子:斐波那契数列的递推公式为。我们如何用矩阵乘法表示它呢?。然而这有什么用处呢?矩阵乘法显然比直接递推更慢啊!事实并非如此,别忘了我们刚才提到的快速幂。既然我们已经把递推公式转化为乘法的形式(虽然是矩阵乘法),那能不能再把多个乘法算式合并成一个乘方算式呢?。有了这个式子,我们只要算出即可直接由和求出。那么怎么快速计算出呢?快速幂即可!但有个需要注意的地方:当指数为零时,如果是数字,,但矩阵应该怎么办呢?我们需要用到神奇的单位矩阵,它的主对角线上的数字为,其它都为,它有个有用的性质:任何矩阵乘以它都会等于本身。代码如下。
struct matrix
{
int a[3][3];
}base,f,imat;
matrix mul(r matrix x,r matrix y)
{
matrix ret;
ret.a[1][1]=(x.a[1][1]*y.a[1][1]+x.a[1][2]*y.a[2][1])%p;
ret.a[1][2]=(x.a[1][1]*y.a[1][2]+x.a[1][2]*y.a[2][2])%p;
ret.a[2][1]=(x.a[2][1]*y.a[1][1]+x.a[2][2]*y.a[2][1])%p;
ret.a[2][2]=(x.a[2][1]*y.a[1][2]+x.a[2][2]*y.a[2][2])%p;
return ret;
}
matrix ksm(r int x)
{
if(!x) return imat;
matrix tmp=ksm(x>>1);
if(x&1) return mul(mul(tmp,tmp),base);
return mul(tmp,tmp);
}
//f[1][1]=f[2][1]=base[1][1]=base[1][2]=base[2][1]=imat[1][1]=imat[2][2]=1