1. 程式人生 > >Codeforces Round #420 (Div. 2) E. Okabe and El Psy Kongroo(矩陣)

Codeforces Round #420 (Div. 2) E. Okabe and El Psy Kongroo(矩陣)

clu blank his 題目 pri 狀態 oid c++ class

題目鏈接: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\n",ans[15]); 58 return 0; 59 }
View Code

Codeforces Round #420 (Div. 2) E. Okabe and El Psy Kongroo(矩陣)