Codeforces Round #420 (Div. 2)

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

题意:起初在(0,0),现在要求走到(k,0),问你存在多少种走法。 其中有n条线段,每条线段为(a,y)->(b,y),代表如果x坐标走到[a,b]之间时,处于的y坐标要小于这个线段的y坐标,就是只能在线段的下方走(包括刚好在线段上),并且前一个段线段的x坐标与后一个线段的x坐标相同。

思路:dp[i][j]代表从起点走到(i,j)时的走法,那么dp[i][j]=dp[i-1][j]+dp[i-1][j-1]+dp[i-1][j+1]。由于dp[i]只由dp[i-1]转移过来,所以可以忽略i这一维,由于y坐标比较少,x坐标比较大,所以通过矩阵快速幂来优化。

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<time.h>
#include<stack>
#include<cmath>
using namespace std;
typedef long long int LL;
const LL INF = 9223372036854775807;
const int MAXN = 100 + 24;
const int MAXX = 16 + 24;
const int mod = 1e9 + 7;
struct Node{
    LL l, r, y;
}P[MAXN];
struct Matrix{
    int row, col;
    LL m[MAXX][MAXX];
    void init(int row, int col){
        this->row = row;
        this->col = col;
        for (int i = 0; i < row; ++i)
            for (int j = 0; j < col; ++j)
                m[i][j] = 0;
    }
}C;
Matrix operator*(const Matrix & a, const Matrix& b){
    Matrix res;
    res.init(a.row, b.col);
    for (int k = 0; k < a.col; ++k){
        for (int i = 0; i < res.row; ++i){
            if (a.m[i][k] == 0) continue;
            for (int j = 0; j < res.col; ++j){
                if (b.m[k][j] == 0) continue;
                res.m[i][j] = (a.m[i][k] * b.m[k][j] + res.m[i][j]) % mod;
            }
        }
    }
    return res;
}
Matrix operator+(const Matrix & a, const Matrix& b){
    Matrix res;
    res.init(a.row, b.col);
    for (int i = 0; i< a.col; ++i){
        for (int j = 0; j < res.row; ++j){
            res.m[i][j] = (a.m[i][j] + b.m[i][j]) % mod;
        }
    }
    return res;
}
Matrix Mpow(Matrix A, LL n){
    Matrix ans = A, p = A;
    while (n){
        if (n & 1){
            ans = ans*p; n--;
        }
        n >>= 1; p = p*p;
    }
    return ans;
}
int main(){
//#ifdef kirito
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//#endif
//    int start = clock();
    int n; LL k;
    while (~scanf("%d%lld",&n,&k)){
        for (int i = 0; i < n; i++){
            scanf("%lld%lld%lld", &P[i].l, &P[i].r, &P[i].y);
        }
        C.init(16, 1);  C.m[0][0] = 1; 
        for (int i = 0; i < n; i++){
            if (P[i].l >= k){
                break;
            }
            Matrix res; res.init(16, 16);
            for (int j = 0; j < 16; j++){
                if (j>P[i].y){
                    break;
                }
                for (int q = -1; q <= 1; q++){
                    if (j + q >= 0 && j + q <= P[i].y){
                        res.m[j][j + q] = 1;
                    }
                }
            }
            res = Mpow(res, min(k,P[i].r) - min(k,P[i].l)-1); //超过k的不需计算
            for (int j = P[i].y + 1; j < 16; j++){ //超过线段y坐标的走法不存在,置0
                C.m[j][0] = 0;
            }
            C = C*res;
        }
        printf("%lld
", C.m[0][0]);
    }
//#ifdef LOCAL_TIME
//    cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
    return 0;
}
原文地址:https://www.cnblogs.com/kirito520/p/7094879.html