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

题目链接: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 }
View Code
原文地址:https://www.cnblogs.com/bin-gege/p/7084464.html