题意:我们现在位于(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 ",ans.a[0][0]); return 0; }