反射容斥

反射容斥

单直线问题:

每次只能向上走一格或向右走一格,求不碰到 \(y=x+b\) 从 \((0,0)\) 走到 \((s,t)\) 的方案数。

如图就是一条错误的路线。

考虑将终点沿这条直线翻折:

发现每一条错误的路线都唯一对应一条从 \((0,0)\) 走到 \((s-b,t+b)\) 的路线(就是原点到翻折后的点)。

求从原点走到某个点的方案数是容易的:即在一共 \(s+t\) 步中选择 \(s\) 步往右走,其他 \(t\) 步往上走。或是在 \(s+t\) 步中选择 \(t\) 步往上走,其他 \(s\) 步往右走,这两者数学上本来也是等价的。

\[\binom{s+t}{s}=\binom{s+t}{t} \]

所以答案就是:

\[\binom{s+t}{s}-\binom{s-b+t+b}{t+b}=\binom{s+t}{s}-\binom{s+t}{t+b} \]

双直线问题:

这是本文的重点。

现有两条直线 \(A:y=x+a,B=y=x+b\) 。求不碰到 \(A,B\) 从 \((0,0)\) 走到 \((s,t)\) 的方案数。

一个大致的想法是,算出碰到直线 \(A\) 的方案数 \(f(A)\) ,以及碰到直线 \(B\) 的方案数 \(f(B)\) 。

然后:

\[\binom{s+t}{s}-f(A)-f(B)+同时碰到AB的方案数 \]

但难就难在算出同时碰到 \(AB\) 的方案数。

我们可以进行如下考虑:

先将 \((s,t)\) 沿 \(B\) 翻折得到绿点 \((t-b,s+b)\) ,这样从 \((0,0)\) 到 \((t-b,s+b)\) 的绿色路线就都碰到了 \(B\) 。

那么如果还要碰到 \(A\) 的话,就需要绿色线碰到翻折过后的 \(A\) ,(蓝色线)。

那么将绿点继续沿蓝色线翻折得到黄色点 \((s+a-b,t-a+b)\) 。

这样从 \((0,0)\) 到 \((s+a-b,t-a+b)\) 的线就经过了 \(A,B\) 。

但是聪明的你一定会发现这样会统计漏:

如果在第一次碰到 \(B\) 之前我碰到了 \(A\) 那我就不用要求后半段碰到 \(A\) 了。

所以我们可以把刚刚的做法对 \(A\) 直线同样做一次:

先将 \((s,t)\) 沿 \(A\) 翻折得到 \((t-a,s+a)\) ,这样从 \((0,0)\) 到 \((t-a,s+a)\) 的路线就都碰到了 \(A\) 。

那么如果还要碰到 \(B\) 的话,就需要这条路线碰到翻折过后的 \(B\) 。

\(.....\)

不妨把第一次的结果记为 \(f(BA)\) (先经过 \(B\) ,再经过 \(A\) ),第二次记为 \(f(AB)\) (先经过 \(A\) ,再经过 \(B\)) 。

然后我们考虑这样真的就做完了吗?

并没有。

因为这样会算重。

如果某条路线先经过了 \(A\) ,然后是 \(B\) ,然后又经过了 \(A\) 。那么 \(f(AB)\) 和 \(f(BA)\) 都会把它算一次。

同理,如果某条路线先经过了 \(B\) ,然后是 \(A\) ,然后又经过了 \(B\) 。那么 \(f(AB)\) 和 \(f(BA)\) 也都会把它算一次。

所以,我们必须减去这两者的方案数。

当然这就是 \(f(ABA)\) 和 \(f(BAB)\) 。

相信你也发现了,这样 \(ABAB\) 和 \(BABA\) 还会算重,所以我们继续容斥掉这两者。

所以这是一个递归下去的问题。

\[\binom{s+t}{s}-f(A)-f(B)+f(AB)+f(BA)-f(ABA)-f(BAB)+f(ABAB)+f(BABA)-... \]

而我们知道 \(f\) 的值是很好算的(就是类似上面的,不断翻折几次)。

而且这个式子只有有限项,因为后面点的坐标会被越翻越离开一象限,导致对应 \(f\) 的值为 \(0\) ,没有统计的必要。

以 \(f(A...)\) 为例:

此时:

  • \(A\) : \((t-a,s+a)\)

  • \(AB\) : \((s+b-a,t-b+a)\)

  • \(ABA\) : \((t-2a+b,s+2a-b)\)

  • \(ABAB\) : \((s+2b-2a,t-2b+2a)\)

上述例子已经说明,在有限项后,该点的横坐标会小于 \(0\) ,此时方案数为 \(0\) ,对应的 \(f\) 为 \(0\) 。

时间复杂度:

\[O((s+t)/(a-b)) \]

posted @ 2026-10-18 12:30  wlhao  阅读(3)  评论(0)    收藏  举报