poj3070
题意:让求斐波那契数列,其n更是高达10亿。
直接递推的局限性:
(1)本题让你递推的斐波那契数n高达10亿。测试时间仅1秒的时间,for循环用递推公式递归导致超时。
(2)想要打表实现随机访问根本不可能,先把斐波那契数列求到10亿,然后想去进行随机访问。题目未给出那么多内存,数组也开不到10亿。
请基于对线性代数的学习后,了解了矩阵的概念及基本运算再继续下面的阅读。
引入: 整数快速幂
为了引出矩阵的快速幂,以及说明快速幂算法的好处,我们可以先求整数的幂。
比如要求x8,如果直接xxx……要进行7次的乘法运算;
但是如果先对它*x,变成x2,那就只需要1+3次;
现在要考虑应该怎么分让计算比较快。接下来计算整数快速幂。例如:x19次方。
19的二进制:10011
就可以变成x16× x2× x
int QuickPow(int x,int N)
{
int res = x;
int ans = 1;
while(N)
{
if(N&1)
{
ans = ans * res;
}
res = res*res;
N = N>>1;
}
return ans;
}
矩阵快速幂
矩阵的乘法
const int N=100;
int c[N][N];
void multi(int a[][N],int b[][N],int n)//n是矩阵大小,n<N
{
memset(c,0,sizeof c);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
c[i][j]+=a[i][k]*b[k][j];
}
快速幂
板子1
struct Matrix {//结构体,矩阵类型
int m[1000][1000];
}ans,res;
/*计算矩阵乘法的函数,参数是矩阵a,矩阵b,和一个n代表两个矩阵是几阶方阵*/
Matrix Mul(Matrix A, Matrix B, int n) {
Matrix tmp;//临时矩阵,存放A*B的结果
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
tmp.m[i][j] = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
for (int k = 1; k <= n; k++)
tmp.m[i][j] += A.m[i][k] * B.m[k][j];
return tmp;
}
//快速幂算法,求矩阵的res的n次幂
void QuickPower(int N, int n) {
/*上面整数的幂的ans初始化是1,对于矩阵来说,ans应该初始化为单位矩阵*/
for(int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
if (i == j)ans.m[i][j] = 1;
else ans.m[i][j] = 0;
}
while (N) {
if (N & 1)
ans = Mul(ans, res, n);
res = Mul(res, res, n);
N = N >> 1;
}
}
板子2
const int N=10;
int tmp[N][N];
void multi(int a[][N],int b[][N],int n)
{
memset(tmp,0,sizeof tmp);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
tmp[i][j]+=a[i][k]*b[k][j];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i][j]=tmp[i][j];
}
int res[N][N];
void Pow(int a[][N],int n)
{
memset(res,0,sizeof res);//n是幂,N是矩阵大小
for(int i=0;i<N;i++) res[i][i]=1;
while(n)
{
if(n&1)
multi(res,a,N);//res=res*a;复制直接在multi里面实现了;
multi(a,a,N);//a=a*a
n>>=1;
}
}
这些代码看看就好,模板建议还是自己写的好,自己怎么写顺溜就怎么写呗,弄清楚原理就好。
运用
那我们上面没解决的斐波那契的问题就有了方法:
观察f[n] = f[n-1]+f[n-2] 第n相是由第n-1项和第n-2项递推而来。
同理,第n+1项由第n项和第n-1项递推而来。
因此可以用矩阵递推式表示:
简写成T * A(n-1)=A(n),T矩阵就是那个2*2的常数矩阵(转移矩阵)
A(n)就是
构建矩阵递推的大致套路
一般An与A(n-1)都是按照原始递推式来构建的,当然可以先猜一个An,主要是利用矩阵乘法凑出矩阵T,第一行一般就是递推式,后面的行就是不需要的项就让相乘为0。矩阵T能把A(n-1)转移到A(n);然后这就是个等比数列,直接写出通项:此处A1叫初始矩阵。所以用一下矩阵快速幂然后乘上初始矩阵就能得到An,这里An就两个元素(两个位置),根据自己设置的A(n)对应位置就是对应的值,按照上面矩阵快速幂写法,res[1][1]=f(n)就是我们要求的。