[Codeforces1225E]Rock Is Push

题意

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

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

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

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

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


样例 3 3 3的动图


题解

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

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

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

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

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

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

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

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

C n t D i , j CntD_{i,j} CntDi,j表示从 ( i , j ) (i,j) (i,j)向下到 ( n , j ) (n,j) (n,j)有多少箱子, C n t R i , j CntR_{i,j} CntRi,j表示从 ( i , j ) (i,j) (i,j)向右到 ( i , m ) (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}} Ri,j+1,...,Ri,mCntRi+1,j都要加上 R i , j + D i , j R_{i,j}+D_{i,j} Ri,j+Di,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} Di+1,j,...,DnCntDi+1,j,j都要加上 R i , j + D i , j R_{i,j}+D_{i,j} Ri,j+Di,j

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

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

最后答案就是 D n , m + R n , m D_{n,m}+R_{n,m} Dn,m+Rn,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;
	...
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值