动态dp
动态dp,简称DDP,就是可修的动态规划,一般用矩阵优化
1. 前置知识:
一下默认会矩阵乘法。
矩阵维护递推,举个例子:
斐波那契数列: $ f_i = f_{i-1} + f_{i-2}$
我们可以根据造转移矩阵的方法递推。
\[\begin{bmatrix} f_{i-1} & f_{i-2}\end{bmatrix} \times \begin{bmatrix} 1 & 1\\ 1 & 0\end{bmatrix} = \begin{bmatrix} f_i & f_{i-1} \end{bmatrix}
\]
且矩阵满足分配律,(注意不满足交换律),我们设转移矩阵为 \(C\),那么我们求 \(f_x\) 只需算出 \(\begin{bmatrix} 1 &1\end{bmatrix} \times C \times ... \times C\),\(x-2\) 个 \(C\),得到结果的矩阵第一个元素既是 \(f_x\),所以我们可以进行矩阵快速幂优化为 \(O(logn)\)。
I P1939 矩阵加速(数列)
模版,只需建出转移矩阵
\[\begin{bmatrix}1 & 1 & 0\\ 0 & 0 & 1\\ 1 & 0 & 0\end{bmatrix}
\]
跑矩阵快速幂即可。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
ll t,n;
struct Matrix{
ll a[4][4],n,m;
void clear(){n = m = 0;memset(a,0,sizeof a);}
Matrix operator * (Matrix x){
Matrix y;y.clear();y.n = n,y.m = m;
for(int i = 1;i <= n;i++)
for(int j = 1;j <= m;j++)
for(int k = 1;k <= m;k++)y.a[i][j] = (y.a[i][j] + a[i][k] * x.a[k][j]) % mod;
return y;
}
}C,st,f,s;
int main(){
scanf("%d",&t);
st.n = 1,st.m = 3;
st.a[1][1] = st.a[1][2] = st.a[1][3] = 1;
C.n = C.m = 3;
C.a[1][1] = 1,C.a[3][1] = 1,C.a[1][2] = 1,C.a[2][3] = 1;
while(t--){
scanf("%lld",&n);
if(n <= 3)printf("1\n");
else{
n -= 3;
f = st,s = C;
while(n){
if(n & 1)f = f * s;
s = s * s;
n >>= 1;
}
printf("%lld\n",f.a[1][1]);
}
}
return 0;
}