一提起幂,大家一定会不约而同的想到pow函数。前一段时间的期末,帮外院的同学备考C语言的时候,发现他们有的函数题或者编程题有特殊要求,就比如不能用某某头文件或某某函数。
如果不让用#include
int sxpow(int a,int n)
{
int ans=1;
for(int i=1; i<=n; i++)
ans*=a;
return ans;
}
学过计算机语言的都明白,是不是慢极了?来来来,快速幂。
快速幂就是快速的算幂(有点废话),时间复杂度为 O(log₂N), 与上面的 O(N)相比效率有了极大的提高。
二进制快速幂
先补充一下位运算的小知识:
来个模板(以a¹¹为例)
int fastpow(int a,int n)
{
int base=a;//也可以不定义base,直接用a来计算,这里是为了方便解释
int res=1;//用res返回结果
while(n)
{
if(n&1)//如果n的最后一位是1,表示这个地方需要乘
res*=base;
base*=base;//推算乘积,a2->a4->a8....
n>>=1;//n右移一位,把刚处理过的n的最后一位去掉
}
return res;
}
对于上面的程序,执行步骤为:
一般式快速幂 (这个就和上边的位运算求幂的模板一样,就是把个别的运算式换了一种表达方法)
int fastpow(int a,int n)
{
int base=a;
int res=1;
while(n)
{
if(n%2)
res*=base;
base*=base;
n/=2;
}
return r;
}
递归式快速幂
int fastpow(int a,int n)
{
if(n==1)
return a;//分治
int temp=fastpow(a,n/2);
if(n%2==1)//奇数个a,可以写n&1
return temp*temp*a;
else //偶数个a
return temp*temp;
}
矩阵快速幂
下为矩阵相乘的定义和公式
(该图片出自百度百科)
矩阵乘法的代码,结合着上图来看就比较好理解了。
同样,矩阵乘法也满足乘法的一些基本性质(交换律,结合律,分配律等等)。
struct node
{
int mat[15][15];//定义矩阵
} x,y;
node mul(node x,node y) //矩阵乘法
{
node tmp;
for(int i=0; i
给定一个m X m的矩阵A,求它的n次幂,原理就是把矩阵当成变量来操作。所以,矩阵快速幂和快速幂的模板也是大同小异。
node matpow(node x,node y,int num) //矩阵快速幂
{
while(num)
{
if(num&1)
y=mul(y,x);
x=mul(x,x);
num=num>>1;
}
return y;
}
矩阵乘法的复杂度是O(len³),快速幂的复杂度为O(log₂num),所以矩阵快速幂的时间复杂度为O(len³ X log₂num)。
矩阵快速幂的应用主要是用来求解递推式,如何把递推关系转换为矩阵却是很大的一个难点。
下图为一些常见的递推关系转换为矩阵的模型,大家自行食用。
(该图片转自https://blog.csdn.net/red_red_red/article/details/90208713)
幂运算的结果一般会非常大,通常会超过变量类型的最大值,甚至超过内存所放的最大数,所以这类题目一般会要求取模,缩小结果。
根据模运算的性质,在快速幂中取模操作,对aⁿ取模,和先对a取模再做幂运算的结果是一样的,也就是:
aⁿ mod m = (a mod m)ⁿ mod m
以一般式快速幂为例:
if(n%2)
res=(res*base)%mod;
base=(base*base)%mod;
HDU 1061--求nⁿ的末尾数字
HDU 5392--快速幂取模
POJ 3070--矩阵快速幂的经典题目,算Fibonacci数列
HDU 6030--把递推关系转换成矩阵(女生专场竞赛题目)
HDU 5895--有难度的矩阵快速幂(2016 ACM/ICPC Asia Regional Shenyang Online )
就先推荐这些,大部分题目都是模板题,大家可以自己去学校官网找一些适合自己的题目来AC一下 ( ̄▽ ̄)~*