题目链接:Codeforces Round #420 (Div. 2) E. Okabe and El Psy Kongroo
题意:
在一个二维方格子里有n条线段,有三种走法
(x + 1, y + 1), (x + 1, y), or (x + 1, y - 1).
现在要求每次都要在线段下行走,问你有多少种走法,
可以从(0,0)到(k,0)。
题解:
考虑dp f[i][j]=f[i-1][j]+f[i-1][j+1]+f[i-1][j-1]。
由于k比较大c比较小,可以考虑用矩阵来优化。
将每一个yi看做一个向量。过渡矩阵满足上面的DP方程即可。
这样就可以快速的处理每条线段的状态转移。
然后再对每两条线段的过度处理一下就行了。
1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);i++) 4 using namespace std; 5 typedef long long ll; 6 7 const int mat_N=16,mo=1e9+7; 8 struct mat{ 9 ll c[mat_N][mat_N]; 10 void init(){mst(c,0);} 11 mat operator*(mat b){ 12 mat M;int N=mat_N-1;M.init(); 13 F(i,0,N)F(j,0,N)F(k,0,N)M.c[i][j]=(M.c[i][j]+c[i][k]*b.c[k][j])%mo; 14 return M; 15 } 16 mat operator^(ll k){ 17 mat ans,M=(*this);int N=mat_N-1;ans.init(); 18 F(i,0,N)ans.c[i][i]=1; 19 while(k){if(k&1)ans=ans*M;k>>=1,M=M*M;} 20 return ans; 21 } 22 }TR,now; 23 24 int n; 25 ll ans[16],tmp[16],k; 26 27 void del(int h) 28 { 29 TR.init(); 30 F(i,15-h,15) 31 { 32 if(i-1>=0)TR.c[i][i-1]=1; 33 TR.c[i][i]=1; 34 if(i+1<=15)TR.c[i][i+1]=1; 35 } 36 } 37 38 int main() 39 { 40 scanf("%d%I64d",&n,&k); 41 ans[15]=1; 42 F(i,1,n) 43 { 44 ll l,r,h; 45 scanf("%I64d%I64d%I64d",&l,&r,&h); 46 del(h),now=TR^(min(r-l,k-l)); 47 F(i,0,(14-h))ans[i]=0; 48 F(i,0,15) 49 { 50 tmp[i]=0; 51 F(j,0,15)tmp[i]+=(now.c[i][j]*ans[j])%mo; 52 tmp[i]%=mo; 53 } 54 F(i,0,15)ans[i]=tmp[i]; 55 if(k<r)break; 56 } 57 printf("%I64d ",ans[15]); 58 return 0; 59 }