递推(矩阵快速幂)
题目描述
题目链接
JYM和XJ转眼就从小学上了高中。在学习递推的时候,JYM在纸上随手写了一个递推关系式:an=2an-1,a0=0。写完这个递推式,JYM拿给XJ看,XJ觉得太过简单,于是大笔一挥,在等式右边又加了一个式子,变成了这样:an=2an-1+n2。JYM看到这个式子,想要算几个项来看看,可是一算就发现这个数据量太大了,你能帮他解决这个问题吗?
输入描述:
输入数据有多组(不超过100组数据),每组数据包含一个整数N<=1018
输出描述:
一个整数X,表示递推式第n项的值。由于数字太大,因此结果对于1000000009取模后输出。
示例1
输入
0
1
2
3
输出
0
1
6
21
这里通过构建T×Fn-1=Fn型关系式解答(前提知识:矩阵快速幂)
根据递推式an=2*an-1+n2,写出第n项所包含的元素:an,n2
还有第n-1项的元素an-1,(n-1)2
然后考虑如何将(n-1)2转化到n2:(n-1)2+2n-1=n2,所以F矩阵中应当还有n和1这两个元素,现在罗列所有元素,形成矩阵Fn:
[ a n n 2 n 1 ] \left[ \begin{matrix} an \\ n^2 \\ n\\ 1 \end{matrix} \right] ⎣⎢⎢⎡ann2n1⎦⎥⎥⎤
再列出Fn-1:
[
a
n
−
1
(
n
−
1
)
2
n
−
1
1
]
\left[ \begin{matrix} an-1 \\ (n-1)^2 \\ n-1\\ 1 \end{matrix} \right]
⎣⎢⎢⎡an−1(n−1)2n−11⎦⎥⎥⎤
通过两者关系构建转移矩阵T:
[
2
1
2
1
0
1
2
1
0
0
1
1
0
0
0
1
]
\left[ \begin{matrix} 2 & 1 & 2 & 1\\ 0 & 1 & 2 & 1 \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 1 \end{matrix} \right]
⎣⎢⎢⎡2000110022101111⎦⎥⎥⎤
即确定了关系式T*Fn-1=Fn中的每个元素,可通过矩阵快速幂解答
#include<iostream>
#include<cstdio>
#include<cstring>
const int MAXN=4;
const int mod=1000000009;
using namespace std;
struct zhen
{
long long m[MAXN][MAXN];
zhen(){memset(m,0,sizeof(m));}
};
zhen cheng(zhen a,zhen b)
{
zhen res;
for(int i=0;i<MAXN;++i)
for(int j=0;j<MAXN;++j)
for(int k=0;k<MAXN;++k)
res.m[i][j]=(res.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
return res;
}
zhen quick(zhen a,long long n)
{
zhen res,base=a;
for(int i=0;i<MAXN;++i)
res.m[i][i]=1;
while(n)
{
if(n&1)
res=cheng(res,base);
base=cheng(base,base);
n>>=1;
}
return res;
}
int main()
{
long long n;
while(cin>>n)
{
zhen a;
a.m[0][0]=2,a.m[0][1]=1,a.m[0][2]=2,a.m[0][3]=1;
a.m[1][0]=0,a.m[1][1]=1,a.m[1][2]=2,a.m[1][3]=1;
a.m[2][0]=0,a.m[2][1]=0,a.m[2][2]=1,a.m[2][3]=1;
a.m[3][0]=0,a.m[3][1]=0,a.m[3][2]=0,a.m[3][3]=1;
zhen c,res;
c.m[3][0]=1;
a=quick(a,n);
res=cheng(a,c);
cout<<res.m[0][0]<<endl;
}
}