P2106:Sam 数题解

这道题算是一道矩阵递推的模板题吧。不是很了解矩阵乘法或者是矩阵递推加速原理的可以移步这篇 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;
}

Leave a Reply

Your email address will not be published. Required fields are marked *