[Codeforces1225E]Rock Is Push

题意

一个 n × m n\times m 的网格上有一些箱子

你只能向下或者向右走,如果碰到了箱子你可以沿着你行走的方向推动它

与之相连的在同一个方向上的所有箱子会一起向这个方向移动

求从 ( 1 , 1 ) (1,1) 走到 ( n , m ) (n,m) 的方案数在模 1 0 9 + 7 10^9+7 下的结果

1 n , m 2000 1\le n,m\le2000


样例 3 3 的动图


题解

如果不能推动,那就差不多是过河卒了,这题也同样考虑 D P DP

考虑到推动会有向下向右的区别

D i , j / R i , j ( D o w n / R i g h t ) D_{i,j}/R_{i,j}(Down/Right) 表示从 ( 1 , 1 ) (1,1) ( i , j ) (i,j) ,上一步是向下 / / 右走的方案数

初始 D 1 , 1 = R 1 , 1 = 1 D_{1,1}=R_{1,1}=1

假设我们当前在 ( i , j ) (i,j) 且当前位置没有箱子,考虑向右最多能走多少步

假设从 ( i , j + 1 ) (i,j+1) ( i , m ) (i,m) 上有 k k 个箱子,那么我们最多就能向右走 m j k m-j-k

( i , j + 1 ) (i,j+1) ( i , m k ) (i,m-k) 这些格子我都能走到

由于是向右走过来的那么 R i , j + 1 , . . . , R i , m k R_{i,j+1},...,R_{i,m-k} 的方案都要加上 R i , j + D i , j R_{i,j}+D_{i,j}

C n t D i , j CntD_{i,j} 表示从 ( i , j ) (i,j) 向下到 ( n , j ) (n,j) 有多少箱子, C n t R i , j CntR_{i,j} 表示从 ( i , j ) (i,j) 向右到 ( i , m ) (i,m) 有多少箱子

那么就有

R i , j + 1 , . . . , R i , m C n t R i + 1 , j R_{i,j+1},...,R_{i,m-CntR_{i+1,j}} 都要加上 R i , j + D i , j R_{i,j}+D_{i,j}

D i + 1 , j , . . . , D n C n t D i + 1 , j , j D_{i+1,j},...,D_{n-CntD_{i+1,j},j} 都要加上 R i , j + D i , j R_{i,j}+D_{i,j}

区间加法可以使用差分数组进行优化,然后同一列 / / 行求和即可

因为差分只会影响到后面枚举的状态,所以可以直接在原数组上进行修改,然后求前缀和

最后答案就是 D n , m + R n , m D_{n,m}+R_{n,m}

const int Mod=1e9+7;
inline void Plus(int&a,int b){a+=b;a>=Mod?a-=Mod:0;}
int main(){
	...
	for(int i=n;i;--i)
		for(int j=m;j;--j)
			CntD[i][j]+=CntD[i+1][j],CntR[i][j]+=CntR[i][j+1];
	D[1][1]=R[1][1]=1;D[2][1]=R[1][2]=-1;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j){
			Plus(D[i][j],D[i-1][j]);
			Plus(R[i][j+1],D[i][j]),Plus(R[i][m-CntR[i][j+1]+1],Mod-D[i][j]);
			Plus(R[i][j],R[i][j-1]);
			Plus(D[i+1][j],R[i][j]),Plus(D[n-CntD[i+1][j]+1][j],Mod-R[i][j]);
	}
	Ans=(D[n][m]+R[n][m])%Mod;
	...
}

猜你喜欢

转载自blog.csdn.net/BeNoble_/article/details/102844671