题解 P1939 【【模板】矩阵加速(数列)】

奔波儿霸

2018-08-06 07:47:43

Solution

#### 解题思路 这道题目的关键之处在于构造初始矩阵,题目都告诉我们了要用矩阵加速。所以矩阵快速幂是核心所在。 #### 如何构造 我们首先要确定目标矩阵。下面这个矩阵就是我想要的矩阵. $$\begin{bmatrix}F[i]\\F[i-1]\\F[i-2]\end{bmatrix}$$ 那么这个矩阵要怎样算出来。根据题目给出的递推式可以得到下面三个式子 $$f[i] = f[i-1] \times 1 + f[i-2] \times 0 + f[i-3] \times 1$$ $$f[i-1] = f[i-1] \times 1 + f[i-2] \times 0 + f[i-3] \times 0$$ $$f[i-2] = f[i-1] \times 0 + f[i-2] \times 1 + f[i-3] \times 0$$ 通过每一项的系数可以得出初始矩阵为 $$\begin{bmatrix}1&0&1\\1&0&0\\0&1&0\end{bmatrix}$$ 然后我们就可以通过矩阵快速幂进行求解。 值得注意的是,这个矩阵的$N$次方算出来的第一个元素是$F[N+1]$,这样的话我们可以直接在输出的时候输出第二行第一个元素。 #### 附上代码 ```cpp #include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long LL; const int Mod = 1e9+7; int T, n; struct mat{ LL m[5][5]; }Ans, base; inline void init() { memset(Ans.m, 0, sizeof(Ans.m)); for(int i=1; i<=3; i++) Ans.m[i][i] = 1; memset(base.m, 0, sizeof(base.m)); base.m[1][1] = base.m[1][3] = base.m[2][1] = base.m[3][2] = 1; } inline mat mul(mat a, mat b) { mat res; memset(res.m, 0, sizeof(res.m)); for(int i=1; i<=3; i++) { for(int j=1; j<=3; j++) { for(int k=1; k<=3; k++) { res.m[i][j] += (a.m[i][k] % Mod) * (b.m[k][j] % Mod); res.m[i][j] %= Mod; } } } return res; } inline void Qmat_pow(int p) { while (p) { if(p & 1) Ans = mul(Ans, base); base = mul(base, base); p >>= 1; } } int main() { scanf("%d", &T); while (T--) { scanf("%d", &n); if(n <= 3) { printf("1\n"); continue; } init(); Qmat_pow(n); printf("%lld\n", Ans.m[2][1]); } } /* f[i-1] f[i] f[i-2] ----> f[i-1] f[i-3] f[i-2] f[i] = f[i-1] * 1 + f[i-2] * 0 + f[i-3] * 1 f[i-1] = f[i-1] * 1 + f[i-2] * 0 + f[i-3] * 0 f[i-2] = f[i-1] * 0 + f[i-2] * 1 + f[i-3] * 0 so 1 0 1 1 0 0 0 1 0 */ ```