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;
}
原文地址:https://www.cnblogs.com/TnT2333333/p/7097565.html