P3473

· · 题解

题意

现在有一张 N \times M 的网格图,在这张图中有一些障碍物。

现在要求从左下角出发且方向向上,中间只能直行或右转,并且不能重复经过一个点,到达终点路径条数。

答案对k取模。

那么我们就可以发现,右转的过程实质上是在切割大矩形。如图,红线为路径,黑线为矩形。

f_{u,r,d,l,p} 表示在上为 u 下为 d 左为 l 右为 r 的矩阵上方向为 p (其中 0-3 分别表示上右下左)的边上运动时的方案数,那么小矩形就是大矩形的子问题,且满足加法原理。

那么,现在我们不考虑障碍物,就可以得到这样的方程。只要枚举在哪个点的地方转弯即可

f_{u,r,d,l,0}=\Sigma f_{k,r,d,l+1,1} f_{u,r,d,l,1}=\Sigma f_{u+1,k,d,l,2} f_{u,r,d,l,2}=\Sigma f_{u,r-1,k,l,3} f_{u,r,d,l,3}=\Sigma f_{u,r,d-1,k,0}

若考虑障碍物,就有了这样的伪代码

for(int k;;)
f[u][r][d][l][0]+=f[k][r][d][l+1][0]*(路径上无障碍?1:0) 
for(int k;;)
f[u][r][d][l][1]+=f[u+1][k][d][l][1]*(路径上无障碍?1:0)
for(int k;;)
f[u][r][d][l][2]+=f[u][r-1][k][l][2]*(路径上无障碍?1:0)
for(int k;;)
f[u][r][d][l][3]+=f[u][r][d-1][k][3]*(路径上无障碍?1:0)

为方便起见,以下将(路径上无障碍?1:0)简记为 check(k)

但是我们发现,这样复杂度是 O(n^5) 的,显然会超时,必须把 k 的枚举优化掉

我们可以发现一个公式

以向上为例,有如下式子

f_{u,r,d,l,0}=(\Sigma f_{k,r,d,l+1,1} \times check(k) )+f_{u,r,d,l+1,1} \times check(u) =f_{u+1,r,d,l,0}+f_{u,r,d,l+1,1} \times check(u)

没有了 k 的枚举,瞬间变成了 O(n^4) !

但是这样的空间依旧会超,所以我们可以使用滚动数组,然后发现每次枚举的两个子状态都满足行数和列数的和刚好比原状态少 1,所以可以考虑按行列数之和从小到大枚举。

输入终点坐标时,先输入列再输入行,读入时应注意