文章目录
构造矩阵快速幂优化线性递推式
遇到某些线性递推式,我们可以设法构造成矩阵乘积的形式,
像斐波那契数列 f[i]=f[i-1]+f[i-2] ,写成矩阵乘积的好处就是,
由于矩阵乘积具有结合律,我们可以用快速幂来优化。
(矩阵的构造一般不难,把转移矩阵写出来,左边的方阵很好求)
难点还是在于dp的递推式。
另外要注意,运算只要满足结合律,就可以使用快速幂,像max,min,加减乘除都可以。
举个max的例子:
转移方程很容易写出来:
但是这样时间复杂度是O(n * m * m)
我们重新定义矩阵乘法c[i][j]=max(a[i][k]+b[k][j])
,把递推式写成矩阵乘法的形式:
然后就可以用快速幂了。
POJ3734
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
#define re register
const int maxn = 1e4 + 10;
const int mx = 40;
const int mod = 10007;
const ll inf = 34359738370;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
//n个格子染色 4种颜色 求染完后1 3有偶数个的方案数
//a[i] b[i] c[i] 表示染完i个 1 3都为偶数 有一个是偶数 都是奇数
//a[i]=b[i-1]*1+a[i-1]*2
//b[i]=b[i-1]*2+c[i-1]*2+a[i-1]*2
//c[i]=c[i-1]*2+b[i-1]
//写成矩阵乘法的形式 用矩阵快速幂优化
//a[1]=2 b[1]=2 c[1]=0
struct matrix
{
int m[3][3];
void init()
{
memset(m,0,sizeof m);
m[0][0]=1;
m[1][1]=1;
m[2][2]=1;
}
inline matrix operator * (const matrix &f)const
{
matrix ans;
memset(ans.m,0,sizeof ans.m);
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
for(int k=0;k<3;k++)
ans.m[i][j]=(ans.m[i][j]+m[i][k]*f.m[k][j]%mod)%mod;
}