zoukankan      html  css  js  c++  java
  • BZOJ 4417 [Shoi2013]超级跳马

    首先,(dp[i][j])表示到(i)(j)列的方案数,则显然可以写出状态转移方程:

    [dp[i][j] = sum_{k = 1}^{(m + 1) / 2} dp[2 * k - 1][j - 1] + dp[2 * k - 1][j] + dp[2 * k - 1][j + 1] ]

    (2 * k - 1)这个东西不是很优美啊(这玩意怎么构造矩阵……),考虑把奇数(i)和偶数(i)分开考虑,(dp[0][i][j])为到(2 * i)(j)列的方案数,(dp[1][i][j])为到(2 * i - 1)(j)列的方案数。那么,就得到了两个更清真的(转移来自的状态是连续的,而不是一个隔一个)的状态转移方程:

    [dp[0][i][j] = sum_{k = 1}^{(m + 1) / 2} dp[1][k][j - 1] + dp[1][k][j] + dp[1][k][j + 1] ]

    [dp[1][i][j] = sum_{k = 1}^{(m + 1) / 2} dp[0][k - 1][j - 1] + dp[0][k - 1][j] + dp[0][k - 1][j + 1] ]

    这个东西还是很难变成矩阵,因为显然矩阵开不了(m)那么大……

    发现等式右边就是一个前缀和嘛!那么,设

    [f[0/1][i][j] = sum_{k = 1}^{i} dp[0/1][k][j] ]

    那么有:

    [f[1][i][j] = f[1][i - 1][j] + f[0][i - 1][j - 1] + f[0][i - 1][j] + f[0][i - 1][j + 1] ]

    [f0][i][j] = f[0][i - 1][j] + f[1][i][j - 1] + f[1][i][j] + f[1][i][j + 1] ]

    这个就可以构造矩阵了!

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    #define enter putchar('
    ')
    #define space putchar(' ')
    template <class T>
    void read(T &x){
        char c;
        bool op = 0;
        while(c = getchar(), c > '9' || c < '0')
    	if(c == '-') op = 1;
        x = c - '0';
        while(c = getchar(), c >= '0' && c <= '9')
    	x = x * 10 + c - '0';
        if(op) x = -x;
    }
    template <class T>
    void write(T x){
        if(x < 0) putchar('-'), x = -x;
        if(x >= 10) write(x / 10);
        putchar('0' + x % 10);
    }
    
    const int N = 102, P = 30011;
    int n, m;
    struct matrix {
        int g[N][N];
        matrix(){
    	memset(g, 0, sizeof(g));
        }
        matrix(int useless){
    	for(int i = 0; i < n; i++)
    	    for(int j = 0; j < n; j++)
    		g[i][j] = (i == j);
        }
        matrix operator * (const matrix &b){
    	matrix c;
    	for(int k = 0; k < n; k++)
    	    for(int i = 0; i < n; i++)
    		for(int j = 0; j < n; j++)
    		    c.g[i][j] = (c.g[i][j] + g[i][k] * b.g[k][j]) % P;
    	return c;
        }
        void out(){
    	for(int i = 0; i < n; i++)
    	    for(int j = 0; j < n; j++)
    		write(g[i][j]), j == n - 1 ? enter: space;
    	enter;
        }
    } ans, op1, op2;
    
    matrix qpow(matrix a, int x){
        matrix ret(1);
        while(x){
    	if(x & 1) ret = ret * a;
    	a = a * a;
    	x >>= 1;
        }
        return ret;
    }
    int mod(int x){
        return (x % P + P) % P;
    }
    
    int main(){
    
        read(n), read(m);
        ans.g[0][0] = 1;
        for(int i = 0; i < n; i++){
    	if(i) op1.g[i + n][i - 1] = op2.g[i][i + n - 1] = 1;
    	op1.g[i + n][i] = op1.g[i + n][i + n] = op2.g[i][i + n] = op2.g[i][i] = 1;
    	if(i + 1 < n) op1.g[i + n][i + 1] = op2.g[i][i + n + 1] = 1;
    	op1.g[i][i] = op2.g[i + n][i + n] = 1;
        }
        n *= 2;
        ans = qpow(op2 * op1, m / 2 - 1) * ans;
        if(m & 1) write(mod((op2 * op1 * ans).g[n / 2 - 1][0] - ans.g[n / 2 - 1][0])), enter;
        else write(mod((op2 * op1 * ans).g[n - 1][0] - ans.g[n - 1][0])), enter;
    
        return 0;
    }
    
  • 相关阅读:
    Dijkstra模版
    Trie树|字典树的简介及实现
    hdoj_2066一个人的旅行
    什么是java对象的强、软、弱和虚引用
    cxf调用客户端的方法
    CXF几种客户端调用性能
    csf几种调用的性能考虑
    cxf生成服务器端
    CXF在jdk1.6中运行异常解决
    CXF几种客户端调用性能
  • 原文地址:https://www.cnblogs.com/RabbitHu/p/BZOJ4417.html
Copyright © 2011-2022 走看看