题解 P1349 【广义斐波那契数列】
曦行夜落
2019-05-14 16:46:14
### 正解:矩阵乘法
### UPD:LATEX修改完成
这是一种非常神奇的解法,一般来说用来写递推
比如本题,就是一道非常优秀的模板题。
如果按照$f[i]=pf[i-1]+qf[i-2]$来算会导致TLE
那么我们这时候就可以将递推转为累乘,然后利用快速幂即可得到最终答案。
$A=\begin{bmatrix} f_i \\ f_{i-1} \end{bmatrix}$
这是原始的矩阵,下面我们要把它变成:
$A'=\begin{bmatrix} f_{i+1} \\ f_i \end{bmatrix}$
我们要乘以一个矩阵,因为1列2行的矩阵乘以它之后仍得1列2行,故这个矩阵是2列2行的
$T=\begin{bmatrix}a & b\\ c & d \end{bmatrix}$
根据矩阵乘法的定义,可得$f_{i+1}=pf_i+qf_{i-1}=af_i+bf_{i-1}$
故$a=p,b=q$
同理,$f_i=cf_i+df_{i-1}$,易得$c=1,d=0$,所以我们要乘以
$T=\begin{bmatrix}p & q\\ 1 & 0 \end{bmatrix}$
然后因为$A'=AT$,可以得到$A_n=A_1T^{n-1}$,运算量主要在后面,所以使用快速幂,时间复杂度$O(logn)$
#### Q:如果是$f_i=f_{i-1}+f_{i-2}+1$怎么办?
#### A:在矩阵里面添一项1
即:
$A=\begin{bmatrix} f_i \\ f_{i-1} \\ 1 \end{bmatrix}$
$A'=\begin{bmatrix} f_{i+1} \\ f_i \\ 1 \end{bmatrix}$
$f$之间的推导仍然不变,计算$f_{i+1}$的时候记得算上一个1,同时1只要一直不变即可
$T=\begin{bmatrix} 1 & 1 & 1 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{bmatrix}$
#### Q:那所以对于一般性题目怎么做呢?
#### A:首先,观察累加中的每一项,然后有几项就有几行,接下来再列出这个矩阵将会变成什么矩阵,按照递推关系写上系数即可(一般来说不是最后一项的都是一堆0加一个1)
本题代码:(代码中矩阵与讲解中的对称,谨慎Copy)
------------
```cpp
#include<bits/stdc++.h>
#define maxn (10+5)
using namespace std;
long long mod;
struct matrix
{
long long a[maxn][maxn],r,c;
void init()
{
memset(a,0,sizeof(a));
}
void one()
{
memset(a,0,sizeof(a));
for (int i=1;i<=r;++i)
a[i][i]=1;
}
}A,Tb;
matrix operator * (matrix x,matrix y)
{
matrix ans; ans.init();
ans.r=x.r,ans.c=y.c;
for (int k=1;k<=x.c;++k)
for (int i=1;i<=x.r;++i)
for (int j=1;j<=y.c;++j)
ans.a[i][j]=(ans.a[i][j]+(x.a[i][k]*y.a[k][j])%mod)%mod;
return ans;
}
matrix operator ^ (matrix x,long long k)
{
matrix ans; ans.init();
ans.r=ans.c=x.r;
ans.one();
while (k)
{
if (k%2==1) ans=ans*x;
x=x*x;
k/=2;
}
return ans;
}
int main()
{
long long n,p,q;
cin >> p >> q >> A.a[1][1] >> A.a[1][2] >> n >> mod;
A.r=1; A.c=2;
// puts("GG");
if (n<3) puts("1");
else
{
n-=2;
Tb.c=Tb.r=2;
Tb.a[1][1]=0; Tb.a[1][2]=q;
Tb.a[2][1]=1; Tb.a[2][2]=p;
// puts("GG");
Tb=Tb^n;
A=A*Tb;
cout << A.a[1][2] << endl;
}
return 0;
}
```