以前学过的,现在忘了 居然没有做过笔记
又得再学一遍2333
定义
与数学上矩阵乘法相同
如下 (A)是一个 (n*m)的矩阵
[A=left[
egin{matrix}
a_{1,1} & a_{1,2} & a_{1,3}&...a_{1,m} \
a_{2,1} & a_{2,2} & a_{2,3}&...a_{2,m} \
...& ...&...&...\
a_{n,1} & a_{n,2} & a_{n,3}&...a_{n,m}
end{matrix}
ight]
]
如下 (B)是一个 (m*p)的矩阵
[B=left[
egin{matrix}
b_{1,1} & b_{1,2} & b_{1,3}&...b_{1,p} \
b_{2,1} & b_{2,2} & b_{2,3}&...b_{2,p} \
...& ...&...&...\
b_{m,1} & b_{m,2} & b_{m,3}&...b_{m,p}
end{matrix}
ight]
]
如下 (C=A*B (n*p))
[C=left[
egin{matrix}
displaystylesum_{i=1}^{m}a_{1,i}*b_{i,1}& c_{1,2} & c_{1,3}&...c_{1,p} \
c_{2,1} & c_{2,2} & c_{2,3}&...c_{2,p} \
...& ...&...&...\
c_{m,1} & c_{m,2} & c_{m,3}&...c_{m,p}
end{matrix}
ight]
]
可知
[c_{i,j} = displaystylesum_{k=1}^{m}a_{i,k}*b_{k,j}
]
实现
struct matrix
{
ll n,m,c[MAXN][MAXN];
matrix operator *(matrix &B) const
{
matrix C;
C.n = n,C.m = B.m;
for(reg i = 1;i <= n;i++)
for(reg k = 1;k <= B.m;k++)
{
C.c[i][k] = 0;
for(reg j = 1;j <= m;j++)
C.c[i][k] = (C.c[i][k] + c[i][j] * B.c[j][k]) % mod;
}
return C;
}
void pr()
{
for(reg i = 1;i <= n;i++)
{
for(reg j = 1;j <= m;j++)
{
printf("%d ",c[i][j]);
}
putchar('
');
}
putchar('
');
}
};
用途
加快(dp)
例如 P1962 斐波那契数列
动态规划方程为
dp[i] = dp[i - 1] + dp[i - 2]
求 第(n)项
先画个矩阵
[left[
egin{matrix}
0&1\
1&1\
end{matrix}
ight]
]
[left[
egin{matrix}
dp[i]&dp[i + 1]\
end{matrix}
ight]
]
(displaystyleRightarrow^{A*B})
[left[
egin{matrix}
dp[i+1]&d[i+2]\
end{matrix}
ight]
]
看到这里 就明白了了
但是这样 时间并没有减少啊
(Attention)
矩阵乘法满足交换律
[A*B*C=A*(B*C)
]
那么
[left[
egin{matrix}
0&1\
1&1\
end{matrix}
ight]
]
可以使用矩阵快速幂了!!
构建 一个矩阵(B)
(S.T.A*B=A)
在这道题中
[B=left[
egin{matrix}
1&0\
0&1\
end{matrix}
ight]
]
inline matrix qkpow(matrix A,ll n)
{
matrix res;
res.n = res.m = 2,res.c[1][1] = res.c[2][2] = 1;
res.c[1][2] = res.c[2][1] = 0;
while(n)
{
if(n & 1) res = res * A;
n >>= 1;
A = A * A;
}
return res;
}
(Code)
#include <cmath>
#include <cstdio>
#include <climits>
#include <iostream>
#include <algorithm>
using namespace std;
#define isdigit(x) ('0' <= (x)&&(x) <= '9')
#define reg register int
template<typename T>
inline T Read(T Type)
{
T x = 0;
bool f = 0;
char a = getchar();
while(!isdigit(a)) {if(a == '-') f = 1;a = getchar();}
while(isdigit(a)) x = (x << 1) + (x << 3) + a - '0',a = getchar();
if(f) x *= -1;
return x;
}
typedef long long ll;
const int MAXN = 100,mod = 1000000007;
struct matrix
{
ll n,m,c[MAXN][MAXN];
matrix operator *(matrix &B) const
{
matrix C;
C.n = n,C.m = B.m;
for(reg i = 1;i <= n;i++)
for(reg k = 1;k <= B.m;k++)
{
C.c[i][k] = 0;
for(reg j = 1;j <= m;j++)
C.c[i][k] = (C.c[i][k] + c[i][j] * B.c[j][k]) % mod;
}
return C;
}
void pr()
{
for(reg i = 1;i <= n;i++)
{
for(reg j = 1;j <= m;j++)
{
printf("%d ",c[i][j]);
}
putchar('
');
}
putchar('
');
}
};
inline matrix qkpow(matrix A,ll n)
{
matrix res;
res.n = res.m = 2,res.c[1][1] = res.c[2][2] = 1;
res.c[1][2] = res.c[2][1] = 0;
while(n)
{
if(n & 1) res = res * A;
n >>= 1;
A = A * A;
}
return res;
}
int main()
{
ll n = Read(1ll); n -= 1;
matrix A,B;
A.n = 1,A.m = 2,A.c[1][1] = A.c[1][2] = 1;
B.n = B.m = 2,B.c[1][1] = 0,B.c[1][2] = B.c[2][1] = B.c[2][2] = 1;
matrix C = qkpow(B,n);
A = A * C;
printf("%lld",A.c[1][1]);
return 0;
}