HDU 2842 矩阵快速幂
题目
链接
根据题意推出公式:
F
n
=
F
n
−
1
+
2
∗
F
n
−
2
+
1
F_n = F_{n-1} + 2*F_{n-2} +1
Fn=Fn−1+2∗Fn−2+1,然后利用矩阵快速幂。
(
F
n
−
1
F
n
−
2
1
)
∗
(
1
1
0
2
0
0
1
0
1
)
=
(
F
n
F
n
−
1
1
)
\begin{pmatrix}F_{n-1}&F_{n-2}&1\\\end{pmatrix} * \begin{pmatrix}1&1&0\\2&0&0\\1&0&1\end{pmatrix} = \begin{pmatrix}F_n&F_{n-1}&1\\\end{pmatrix}
(Fn−1Fn−21)∗⎝⎛121100001⎠⎞=(FnFn−11)
由上面公式可知,初始矩阵为
(
F
n
−
1
F
n
−
2
1
)
\begin{pmatrix}F_{n-1}&F_{n-2}&1\\\end{pmatrix}
(Fn−1Fn−21),幂次矩阵为
(
1
1
0
2
0
0
1
0
1
)
\begin{pmatrix}1&1&0\\2&0&0\\1&0&1\end{pmatrix}
⎝⎛121100001⎠⎞,可以在
O
(
l
o
g
n
)
O(logn)
O(logn)级别的复杂度求出
F
n
F_n
Fn.
代码:
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
#include<cmath>
using namespace std;
const int mod = 200907;
typedef long long LL;
const int m_size = 3;
const int m_max = 5;
struct node
{
LL d[m_max][m_max];
};
node matrixm(node a, node b)
{
node ans;
for(int i = 0; i < m_max; i++)
for(int j = 0; j < m_max; j++)
ans.d[i][j] = 0;
for(int j = 0; j <m_size; j++)
for(int k = 0; k <m_size; k++)
ans.d[0][j] = (ans.d[0][j]+a.d[0][k]*b.d[k][j])%mod;
return ans;
}
node matrixw(node a, node b)
{
node ans;
for(int i = 0; i < m_max; i++)
for(int j = 0; j < m_max; j++)
ans.d[i][j] = 0;
for(int i = 0; i < m_size; i++)
for(int j = 0; j <m_size; j++)
for(int k = 0; k <m_size; k++)
ans.d[i][j] = (ans.d[i][j]+a.d[k][j]*b.d[i][k])%mod;
return ans;
}
void initres(node &res)
{
for(int i = 0; i < m_max; i++)
for(int j = 0; j < m_max; j++)
res.d[i][j] = 0;
res.d[0][0] = 1;res.d[0][1] = 1;res.d[0][2] = 0;
res.d[1][0] = 2;res.d[1][1] = 0;res.d[1][2] = 0;
res.d[2][0] = 1;res.d[2][1] = 0;res.d[2][2] = 1;
return ;
}
void initans(node &ans)
{
for(int i = 0; i < m_max; i++)
for(int j = 0; j < m_max; j++)
ans.d[i][j] = 0;
ans.d[0][0] = 2;ans.d[0][1] = 1;ans.d[0][2] = 1;
return ;
}
node ppow(node an, node re,LL k)
{
node ans = an;
node res = re;
while(k)
{
if(k&1)
ans = matrixm(ans, res);
res = matrixw(res, res);
k >>= 1;
}
return ans;
}
int main()
{
LL n;
node ans, res;
initans(ans);
initres(res);
while(scanf("%lld", &n)&&n)
{
if(n==1)
{
printf("1\n");
}
else if(n==2)
{
printf("2\n");
}
else
{
node fans = ppow(ans,res,n-2);
printf("%lld\n", fans.d[0][0]);
}
}
return 0;
}