网格图计数问题小结

网格图计数问题

引入

现在我们正在一张 \(n*m\) 的网格上行走,每次只能向上下左右四个方向之一移动一步。

看一个最简单的问题:从 \((0, 0)\) 出发,到达 \((x, y)\) 的最短路径方案数是多少?

很显然,要求路径最短,我们不能走回头路,也就是要求只能往 \((x, y)\) 的方向走。为了方便讨论,我们认为只能往右和往上走。

那么方案数就是组合数 \(C(x+y, x)\) ,考虑其组合意义是一共要走 \(x+y\) 步,其中 \(x\) 步分配给向右走。

这个结论是下面讨论的基础。

更进一步

现在讨论从 \((0, 0)\) 出发,到达一个矩形 \((x1, y1, x2, y2)\) 内的所有点的方案数之和是多少?

直接暴力枚举是 \(O(矩形面积)\) 的,肯定不是我们想要的结果。我们希望更优秀的做法,希望能 \(O(1)\) 做!

\(f(x, y)\) 表示从 \((0, 0)\) 走到 \((x, y)\) 的方案数。

发现:

\[f(x, y)=\sum_{i=0}^{y} f(x-1, i) \]

可以从杨辉三角来理解,也可以考虑组合意义:先到达\((x-1, i)\),然后往上走一步,再直接走到 \((x, y)\),显然是不重不漏的。

容斥一下,可以得到问题的答案为:

\[f(x2+1, y2+1)-f(x2+1, y1)-f(x1, y2+1)+f(x1, y1) \]

可以利用把 \(f(x2+1, y2+1\)\(f(x1, y2+1)\) 暴力拆开证明。

于是只需要计算用这个矩形的四个特征点计算四个组合数就能得到答案,复杂度 \(O(1)\)

再上一层

讨论从一个矩形 \(A\) 内的点出发到另一个矩形 \(B\) 内的点结束的方案数之和。

套用上一个问题的做法,可以做到 \(O(size(A))\) ,但我们不想要这么高的复杂度。

事实上,我们可以反过来考虑:从 \(B\) 的四个特征点出发到达矩形 \(A\) 的方案数。

所以可以把 \(A\) 做同样的四个特征点的拆分,这样计算 \(4*4\) 个组合数就可以解决问题了。

注意要带上容斥系数。

for(int i=1; i<=4; i++) scanf("%d", &X[i]);
for(int i=1; i<=4; i++) scanf("%d", &Y[i]);
p[1]=(node){X[1]-1, Y[1]-1, 1};
p[2]=(node){X[1]-1, Y[2], -1};
p[3]=(node){X[2], Y[1]-1, -1};
p[4]=(node){X[2], Y[2], 1};
p[5]=(node){X[3], Y[3], 1};
p[6]=(node){X[3], Y[4]+1, -1};
p[7]=(node){X[4]+1, Y[3], -1};
p[8]=(node){X[4]+1, Y[4]+1, 1};
ll ans=0;
for(int i=1; i<=4; i++){
    for(int j=5; j<=8; j++){
        ans=(ans+solve(p[i].x, p[i].y, p[j].x, p[j].y, p[i].op, p[j].op)+mod)%mod;
    }
}

最终问题

[AGC018E] Sightseeing Plan

简要题意:给定三个互不相交并保证按从左下到右上位置排序的矩形 \(A, B, C\) ,求从 \(A\) 矩形内的点出发,经过 \(B\) 矩形中的休息点,到达 \(C\) 矩形中的点结束的最短路径方案数之和。

两个方案不同当且仅当起点,在 \(B\) 矩形中的休息点,终点有一个不同或路径经过的点有一个不同。

矩形长\(n\leq 1e6\)

先考虑一个简化版的问题:只需要经过 \(B\) 矩形,不需要考虑休息点。

那么枚举一下进入 \(B\) 形的时候是从右/下边界的那个点进入,复杂度 \(O(n)\)

但是这个问题需要考虑进入 \(B\) 矩形的路径长,实际上就是简化版问题的每条路径乘上(在 \(B\) 矩形中的路径长+1)。

来看一下每条路径在 \(B\) 矩形中的出入点对这条路径的贡献:设出入点坐标是 \((x1, y1), (x2, y2)\) ,贡献即为 \(x2-x1+y2-y1+1\) (注意是点数)。

注意到可以拆开贡献,直接枚举边界就好了。

代码链接:Submission #31603766

posted @ 2022-05-11 19:43  Displace  阅读(386)  评论(0)    收藏  举报