快速幂和矩阵快速幂

一、快速幂

快速幂是一种用于快速计算出a^k\ mod \ p(因为a^k太大,通常需要对一个数取模)的算法。因为较为基础,在此不多做讲解。主要原理:a^k=a^{\frac{k}{2}}*a^{\frac{k}{2}}(k\ mod\ 2=0)a^k=a^{\frac{k}{2}}*a^{\frac{k}{2}}*a(k\ mod\ 2=1)a^k=1(k=0)。因为指数在每次运算中都会缩小一半,时间复杂度为O(log_{2}k)。代码如下。

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;
}

当模数较大时,三个数连乘常常会爆int,所以我们最好把函数设为long\ long。不过在实际应用中,还可能出现爆long\ long的情况...因此我们需要稍作修改。代码如下。

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;
}

二、矩阵快速幂

什么是矩阵快速幂呢?就是普通快速幂中的a变成了一个矩阵。什么情况下会用到矩阵乘法呢?其实,数列的递推公式与矩阵乘法就有着千丝万缕的联系。举个很简单的例子:斐波那契数列的递推公式为f[i]=f[i-1]+f[i-2]。我们如何用矩阵乘法表示它呢?\begin{pmatrix} f[i] & 0\\ f[i-1] & 0 \end{pmatrix}=\begin{pmatrix} 1 &1 \\ 1& 0 \end{pmatrix}*\begin{pmatrix} f[i-1] & 0\\ f[i-2] & 0 \end{pmatrix}。然而这有什么用处呢?矩阵乘法显然比直接递推更慢啊!事实并非如此,别忘了我们刚才提到的快速幂。既然我们已经把递推公式转化为乘法的形式(虽然是矩阵乘法),那能不能再把多个乘法算式合并成一个乘方算式呢?\begin{pmatrix} f[n] & 0\\ f[n-1] & 0 \end{pmatrix}=\begin{pmatrix} 1 &1 \\ 1& 0 \end{pmatrix}^{n-2}*\begin{pmatrix} f[1] & 0\\ f[2] & 0 \end{pmatrix}。有了这个式子,我们只要算出\begin{pmatrix} 1 &1 \\ 1& 0 \end{pmatrix}^{n-2}即可直接由f[1]f[2]求出f[n]。那么怎么快速计算出\begin{pmatrix} 1 &1 \\ 1& 0 \end{pmatrix}^{n-2}呢?快速幂即可!但有个需要注意的地方:当指数为零时,如果是数字,a^0=1,但矩阵应该怎么办呢?我们需要用到神奇的单位矩阵,它的主对角线上的数字为1,其它都为0,它有个有用的性质:任何矩阵乘以它都会等于本身。代码如下。

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

 

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值