Codeforces 821E Okabe and El Psy Kongroo

题意:我们现在位于(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方程比较显然:dp[i][j]+=dp[i-1][j]+dp[-1][j-1]+dp[i-1][j+1]

之后构造一个如下的矩阵即可:

110000..0

011100..0

...

000.....111

同时注意一下矩阵的初始化,因此WA了很多次....

#include<bits/stdc++.h>
using namespace std;
typedef __int64 LL;
const LL MODD=1000000007;
struct mat{
    LL a[17][17];
    void init(int t){
        for(int i=0;i<=t;i++)a[i][i]=1;
    }
    void clear(){
        memset(a,0,sizeof(a));
    }
};
int n;
LL k;
mat mul(mat x,mat y,int t){
    mat h;
    h.clear();
    for(int i=0;i<=t;i++)
        for(int j=0;j<=t;j++)
            for(int k=0;k<=t;k++){
                h.a[i][j]+=(x.a[i][k]%MODD*y.a[k][j]%MODD)%MODD;
                h.a[i][j]%=MODD;
            }
    return h;
}
mat pw(mat x,LL t,int l){
    mat b;
    b.clear();
    b.init(l);
    for(;t;t>>=1,x=mul(x,x,l))
        if(t&1)b=mul(b,x,l);
    return b;    
}
int main(){
    mat p,a,ans;
    p.clear();
    ans.clear();
    for(int i=0;i<=15;i++)
        for(int j=max(0,i-1);j<=min(i+1,15);j++)
            p.a[i][j]=1;
    scanf("%d%I64d",&n,&k);
    a.clear();
    a.a[0][0]=1;
    bool flag=false;
    for(int i=1;i<=n;i++){
        LL l,r;
        int t;
        scanf("%I64d%I64d%d",&l,&r,&t);
        if(r>k){r=k;flag=true;}
        ans=pw(p,r-l,t);
        for(int j=t+1;j<=15;j++)a.a[j][0]=0;
        ans=mul(ans,a,t);
        for(int j=0;j<=t;j++)a.a[j][0]=ans.a[j][0];
        if(flag)break;
    }
    printf("%I64d\n",ans.a[0][0]);
    return 0;
}

 

posted @ 2017-11-07 17:58  NINGLONG  阅读(227)  评论(0编辑  收藏  举报