题解 P3990 【[SHOI2013]超级跳马】

· · 题解

希丰展,看博客

f_{i,1} & f_{i,2} &f_{i,3} &f_{i,4} &f_{i-1,1} &f_{i-1,2} &f_{i-1,3} &f_{i-1,4} \end{bmatrix} \ast \begin{bmatrix} 1 & 1 & 0& 0 & 1& 0 &0 & 0\\ 1& 1& 1 & 0& 0 &1 & 0 &0 \\ 0 & 1 & 1& 1& 0 & 0 & 1 & 0\\ 0 & 0 & 1 & 1 &0 & 0 & 0 &1 \\ 1 & 0 &0 & 0 & 0 &0 & 0 &0 \\ 0& 1 & 0& 0& 0& 0& 0& 0\\ 0& 0& 1& 0& 0 & 0&0&0 \\ 0& 0 & 0& 1 & 0 & 0 & 0 & 0 \end{bmatrix} = \begin{bmatrix} f_{i+1,1} & f_{i+1,2} &f_{i+1,3} &f_{i+1,4} &f_{i,1} &f_{i,2} &f_{i,3} &f_{i,4} \end{bmatrix}

这个式子有亿点长啊

转移矩阵:

1 & 1 & 0& 0 & 1& 0 &0 & 0\\ 1& 1& 1 & 0& 0 &1 & 0 &0 \\ 0 & 1 & 1& 1& 0 & 0 & 1 & 0\\ 0 & 0 & 1 & 1 &0 & 0 & 0 &1 \\ 1 & 0 &0 & 0 & 0 &0 & 0 &0 \\ 0& 1 & 0& 0& 0& 0& 0& 0\\ 0& 0& 1& 0& 0 & 0&0&0 \\ 0& 0 & 0& 1 & 0 & 0 & 0 & 0 \end{bmatrix}

初始矩阵

1 & 1 & 0 & 0 & 1 & 0 & 0 & 0 \end{bmatrix}
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 105, M = 30011;

int n, n2, m;
struct Matrix {
    int a[N][N];
    Matrix () {
        memset(a, 0, sizeof(a));
    }
    int *operator [] (const int &i) {
        return a[i];
    }//重载方括号运算符,写起来方便
    Matrix operator * (const Matrix &b) {
        Matrix c;
        for (int i = 1; i <= n2; ++i)
            for (int j = 1; j <= n2; ++j)
                for (int k = 1; k <= n2; ++k)
                    (c.a[i][j] += a[i][k] * b.a[k][j] % M) %= M;
        return c;
    }//重载乘号
    void Print() {
        for (int i = 1; i <= n2; ++i, puts(""))
            for (int j = 1; j <= n2; ++j)
                printf("%d ", a[i][j]);
        puts("");
    }//调试输出用
}a, b, c;

Matrix Pow(Matrix a, int k) {
    Matrix ans = a; k--;
    for (; k; k >>= 1, a = a * a)
        if (k & 1) ans = ans * a;
    return ans;
}//快速幂

int main() {
    scanf("%d%d", &n, &m);
    if (m <= 2) {
        if (n <= 2 && m <= n) puts("1");
        else puts("0");
        return 0;
    }//特判情况1
    n2 = n << 1;
    for (int i = 1; i <= n; ++i) {//构造转移矩阵
        a[i][i-1] = a[i][i] = a[i][i+n] = a[i+n][i] = 1;
        if (i != n) a[i][i+1] = 1;
    }
    b = Pow(a, m - 2);
    if (n == 1) return printf("%d\n", b[1][1]), 0;//特判情况2
    int s1 = (b[1][n2-1] + b[2][n2-1] + b[n+1][n2-1]) % M;
    int s2 = (b[1][n2] + b[2][n2] + b[n+1][n2]) % M;
    //根据初始矩阵和快速幂后的转移矩阵求得目标矩阵的有用值
    printf("%d\n", (s1 + s2) % M);
    //s1是f[m-1][n-1],s2是f[m-1][n],加起来就是答案
    return 0;
}