题解:CF2204G Grid Path

· · 题解

你们矩阵边长怎么都是 2m 的,不卡常吗?

显然每一行占据一个区间。一个合法的 pattern 可以用唯一的一个区间集合 [l_1,r_1],[l_2,r_2],\cdots,[l_k,r_k] 描述,要求相邻有交,且 l_1=1

我们的目标显然是矩阵快速幂优化,考察有 l_1=1 的限制不好做,于是从下到上倒着对这个 pattern 做 dp,f_{i,l,r} 表示第 [i,n] 行,其中第 i 行占据 [l,r] 的方案数。

转移方程

我们的目标显然是矩阵快速幂优化,所以状态数太多必须考虑某种缩减,记 $s_i$ 表示 $\sum_{1\leq l\leq r\leq i}f_{l,r}$,$t_i$ 表示 $\sum_{i\leq l\leq r\leq m}f_{l,r}$,则有 $\displaystyle f_{i,l,r}=1+s_m-s_{l-1}-t_{r+1}$。 不难想到直接对 $s,t$ 做转移,直接裸拆贡献有 $s'_i=\frac{i(i+1)}{2}(s_m+1)-\sum_{l\leq i}(i-l)s_l-\sum_{r\leq i+1}(r-1)t_r$。 显然可以把 $s,t$ 并排放置用矩阵优化。但是矩阵太大不好,考虑对称性,有 $t_i=s_{m-i+1}$,于是矩阵大小减半。 最后答案显然就是 $s_m-s_{m-1}$。 $O(m^3\log n)$,不带 $8$ 的常数,轻松跑。 感谢 @Snakes。 ```cpp #include<bits/stdc++.h> using namespace std; #define int long long #define MAXN 155 int n,m,mod; inline void chkadd( int &x , int k ){ x += k; if( x >= mod ) x -= mod; } struct matrix{ int a[MAXN][MAXN]; matrix(){ memset( a , 0 , sizeof( a ) ); } inline int* operator []( int x ){ return a[x]; } inline void build(){ for( int i = 0 ; i < MAXN ; i ++ ) for( int j = 0 ; j < MAXN ; j ++ ) a[i][j] = i == j; } inline matrix operator *( matrix B ){ matrix C; for( int k = 0 ; k < MAXN ; k ++ ) for( int i = 0 ; i < MAXN ; i ++ ) for( int j = 0 ; j < MAXN ; j ++ ) chkadd( C[i][j] , a[i][k] * B[k][j] % mod ); return C; } }R; inline matrix fp( matrix A , int p ){ matrix res; res.build(); while( p ){ if( p & 1 ) res = res * A; A = A * A; p >>= 1; } return res; } signed main(){ scanf("%lld%lld%lld",&n,&m,&mod); if( m == 1 ){ printf("%lld\n",n % mod); return 0; } //来裸配系数 R[0][0] = 1; for( int i = 1 ; i <= m ; i ++ ){ chkadd( R[m][i] , i * ( i + 1 ) / 2 % mod ); chkadd( R[0][i] , i * ( i + 1 ) / 2 % mod ); for( int j = 1 ; j <= i ; j ++ ) chkadd( R[j][i] , ( mod - ( i - j + mod ) % mod ) % mod ); for( int j = 2 ; j <= min( i + 1 , m ) ; j ++ ) chkadd( R[m - j + 1][i] , ( mod * mod - ( j - 1 ) ) % mod ); } //初值? matrix st; st[0][0] = 1; for( int i = 1 ; i <= m ; i ++ ) st[0][i] = i * ( i + 1 ) / 2 % mod; st = st * fp( R , n - 1 ); printf("%lld\n",( st[0][m] - st[0][m - 1] + mod ) % mod); return 0; } ```