Codeforces Round #420 E

 Okabe and El Psy Kongroo

题意:有n条平行x轴的线段,每条线段的起点为(ai,ci),终点为(bi,ci),且满足ai=b(i-1),从起点出发,每次可以往3个方向走,分别为 (x + 1, y + 1), (x + 1, y), or (x + 1, y - 1),且走的过程必须满足0>=y>=ci,求走到(k,0)有多少种走法

思路:dp+矩阵快速幂,

dp[i][0]=dp[i-1][0]+dp[i-1][1]

...........

dp[i][j]=dp[i-1][j]+dp[i-1][j+1]+dp[i-1][j-1]

...........

dp[i][c]=dp[i-1][c]+dp[i-1][c-1]

得到

dp[i][0]        dp[i][1]    ... dp[i][j]  ...     dp[i][c]

  s矩阵 [                                                         ]

dp[i+1][0]   dp[i+1][1] ... dp[i+1][j] ... dp[i+1][c]

每段线段用一次矩阵快速幂

AC代码:

#include "iostream"
#include "string.h"
#include "stack"
#include "queue"
#include "string"
#include "vector"
#include "set"
#include "map"
#include "algorithm"
#include "stdio.h"
#include "math.h"
#define ll long long
#define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
#define mem(a) memset(a,0,sizeof(a))
using namespace std;
const int N=20;
ll M,Mod=1e9+7;
struct Mat{
    ll m[N][N];
    Mat(){
        mem(m);
    }
    Mat friend operator* (Mat a, Mat b){
        Mat c;
        for(int i=0; i<M; i++)
            for(int j=0; j<M; j++)
            for(int k=0; k<M; k++)
                c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%Mod;
        return c;
    }
};
Mat PowMod(Mat a, ll b){
    Mat c;
    for(int i=0; i<M; ++i) c.m[i][i]=1;
    while(b){
        if(b&1) c=c*a;
        a=a*a;
        b>>=1;
    }
    return c;
}
ll n,k,a[105],b[105],c[105];
int main(){
    cin>>n>>k;
    for(int i=0; i<n; ++i){
        cin>>a[i]>>b[i]>>c[i];
    }
    Mat t;
    for(int i=0;i<16;i++)
        for(int j=i-1;j<=i+1;j++)
            if(j>=0&&j<16)
                t.m[i][j] = 1;
    Mat ans;
    ans.m[0][0]=1;
    for(int i=0; i<n; ++i){
        k-=(b[i]-a[i]);
        M=c[i]+1;
        if(k>=0){
            ans=ans*PowMod(t,b[i]-a[i]);
        }
        else{
            k+=(b[i]-a[i]);
            ans=ans*PowMod(t,k);
        }
    }
    cout<<ans.m[0][0];
    return 0;
}
/*
1 3
0 3 3
2 6
0 3 0
3 10 2
*/
原文地址:https://www.cnblogs.com/max88888888/p/7102892.html