这道题算是一道矩阵递推的模板题吧。不是很了解矩阵乘法或者是矩阵递推加速原理的可以移步这篇 Wiki:矩阵 – OI Wiki.我们很快可以推出一个 DP 方程出来,其中\(i\)代表位数,\(j\)代表第一位所填的数:
\[dp[i][j] = \sum^{j+2}_{k=j-2}dp[i-1][k]\]
然后,我们可以根据这个来推出一个递推矩阵:
\[\left[ \begin{array}{ccc}
1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\
1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0 & 0\\
1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0 & 0\\
0 & 1 & 1 & 1 & 1 & 1 & 0 & 0 & 0 & 0\\
0 & 0 & 1 & 1 & 1 & 1 & 1 & 0 & 0 & 0\\
0 & 0 & 0 & 1 & 1 & 1 & 1 & 1 & 0 & 0\\
0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 1 & 0\\
0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1 & 1\\
0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1 & 1\\
0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 & 1 & 1\\
\end{array} \right]\]
初始矩阵是这样的:
\[\left[ \begin{array}{ccc}
0 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1\\
\end{array} \right]\]
代码如下:
// P2106.cpp #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #define ll long long using namespace std; const ll mod = 1000000007; struct matrix { ll mat[10][10]; matrix() { memset(mat, 0, sizeof(mat)); } matrix operator*(const matrix &ma) const { matrix empt; for (ll i = 0; i < 10; i++) for (ll j = 0; j < 10; j++) for (ll k = 0; k < 10; k++) empt.mat[i][j] = (empt.mat[i][j] + mat[i][k] * ma.mat[k][j] % mod) % mod; return empt; } matrix operator^(const ll &num) const { ll tim = num; matrix pre = *(this); matrix tmp; for (ll i = 0; i < 10; i++) tmp.mat[i][i] = 1; while (tim) { if (tim & 1) tmp = tmp * pre; pre = pre * pre; tim >>= 1; } return tmp; } } premat, Dmat; int main() { ll k; scanf("%lld", &k); if (k == 1) { printf("%lld", 10); return 0; } for (ll i = 1; i < 10; i++) premat.mat[0][i] = 1; for (ll i = 0; i < 10; i++) for (ll j = i - 2; j <= i + 2; j++) { if (j < 0) continue; if (j > 9) break; Dmat.mat[j][i] = 1; } Dmat = Dmat ^ (k - 1); premat = premat * Dmat; ll ans = 0; for (ll i = 0; i < 10; i++) ans += premat.mat[0][i], ans %= mod; printf("%lld", ans); return 0; }