zoukankan      html  css  js  c++  java
  • codeforces E. Okabe and El Psy Kongroo(dp+矩阵快速幂)

    题目链接:http://codeforces.com/contest/821/problem/E

    题意:我们现在位于(0,0)处,目标是走到(K,0)处。每一次我们都可以从(x,y)走到(x+1,y-1)或者(x+1,y)或者(x+1,y+1)三个位子之一。

    现在一共有N段线段,每条线段都是平行于X轴的。我们如果此时x是在这段线段之内的话,我们此时走到的点(x,y)需要满足0<=y<=Ci.

    现在保证一段线段的终点,一定是下一段线段的起点。问我们从起点走到终点的行走方案数。

    题解:简单的dp+矩阵快速幂的模版

    显然如果k很小是个很简单的dp,dp[i][j]=dp[i-1][j]+dp[i-1][j-1]+dp[i-1][j+1]。但是k很大所以就要用到矩阵快速幂,一般像这种递推方程式都是可以化为用矩阵来求的

    dp[1]  110000000000000  predp[1]

    dp[2]  111000000000000  predp[2]

    dp[3]  011100000000000  predp[3]

    dp[4]  001110000000000  predp[4]

    .

    .

    .

    dp[15]  000000000000011  predp[15]

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #define mod 1000000007
    using namespace std;
    typedef long long ll;
    struct Matrix {
        ll dp[17][17];
    };
    Matrix Mul(Matrix a , Matrix b , ll Max) {
        Matrix c;
        memset(c.dp , 0 , sizeof(c.dp));
        for(ll i = 0 ; i <= Max ; i++) {
            for(ll j = 0 ; j <= Max ; j++) {
                for(int k = 0 ; k <= Max ; k++) {
                    c.dp[i][j] += ((a.dp[i][k]) % mod * (b.dp[k][j]) % mod) % mod;
                    c.dp[i][j] %= mod;
                }
            }
        }
        return c;
    }
    Matrix Matrix_quick_pow(Matrix a , ll k , ll Max) {
        Matrix res;
        memset(res.dp , 0 , sizeof(res.dp));
        for(ll i = 0 ; i <= Max ; i++) res.dp[i][i] = 1;
        while(k) {
            if(k & 1) res = Mul(res , a , Max);
            k >>= 1;
            a = Mul(a , a , Max);
        }
        return res;
    }
    int main() {
        ll n , k;
        scanf("%lld%lld" , &n , &k);
        Matrix ans , ope , pre;
        memset(ope.dp , 0 , sizeof(ope.dp));
        memset(pre.dp , 0 , sizeof(pre.dp));
        for(int i = 0 ; i < 16 ; i++) {
            if(i == 0) {
                ope.dp[i][i] = 1;
                ope.dp[i][i + 1] = 1;
            }
            else if(i == 15) {
                ope.dp[i][i] = 1;
                ope.dp[i][i - 1] = 1;
            }
            else {
                ope.dp[i][i] = 1;
                ope.dp[i][i + 1] = 1;
                ope.dp[i][i - 1] = 1;
            }
        }
        pre.dp[0][0] = 1;
        for(int i = 1 ; i <= n ; i++) {
            ll a , b , Max , flag = 0;
            scanf("%lld%lld%lld" , &a , &b , &Max);
            if(b > k) {b = k , flag = 1;}
            ans = Matrix_quick_pow(ope , b - a , Max);
            for(ll j = Max + 1 ; j < 16 ; j++) pre.dp[j][0] = 0;
            ans = Mul(ans , pre , Max);
            for(ll j = 0 ; j <= Max ; j++) {
                pre.dp[j][0] = ans.dp[j][0];
            }
            if(flag) break;
        }
        printf("%lld
    " , ans.dp[0][0]);
        return 0;
    }
    
  • 相关阅读:
    python正则表达式
    正则表达式
    python装饰器
    冒泡排序算法与递归
    C语言typedef定义结构体数组,下面这段代码是什么意思?
    链表实现的简单循环队列
    数组实现的简单循环队列
    悬空指针
    NULL代表什么
    Unity学习——Network Transform和 Network Transform Child组件
  • 原文地址:https://www.cnblogs.com/TnT2333333/p/7097565.html
Copyright © 2011-2022 走看看