1108T4题解

收藏:0

补全证明:棋盘格子配对问题


一、从格子配对到二分图最大匹配

1. 图模型

当前棋盘是 $n \times n$ 的,每个格子要么黑要么白。我们要选出若干对格子 $((x_1,y_1),(x_2,y_2))$,满足:

  1. $(x_1,y_1)$ 是白,$(x_2,y_2)$ 是黑;
  2. 在同一行或同一列;
  3. 每个格子最多被用一次。

用图论语言建模:

  • 把所有白格子作为二分图左部的点;
  • 把所有黑格子作为二分图右部的点;
  • 如果一个白格子和一个黑格子在同一行或同一列,就在它们之间连一条边。

那么:

  • 一条边对应一个合法的格子对(白 → 黑)。
  • 一组互不相交的边(没有公共端点)对应一组互不相交的格子对。

因此: 要选的格子对数量 = 这个二分图的最大匹配大小

这就证明了“答案即为二分图最大匹配”的那一步。


二、从最大匹配到最大独立集

一个小知识:在任意图中,有如下关系: $$ \text{最大独立集大小} + \text{最小点覆盖大小} = |V| $$ 其中 $|V|$ 为点数。

二分图中还有著名的 Kőnig 定理

在任何二分图中: 最大匹配大小 = 最小点覆盖大小

于是对我们这个二分图: $$ \text{最大匹配} = \text{最小点覆盖} = |V| - \text{最大独立集} $$

本题中点就是所有格子,数量为 $n^2$。于是: $$ \text{答案} = \text{最大匹配大小} = n^2 - \text{最大独立集大小} $$

所以求最大匹配 ⇔ 求最大独立集,求后者更方便做结构分析。


三、最大独立集在棋盘上的结构

回忆一下图的定义:

  • 点:每个格子(带颜色);
  • 边:同一行或同一列中,颜色不同的一对格子。

独立集:点集 $I$,其中任意两点之间没有边。 也就是:不会出现同一行 / 列中同时选了一个黑格子和一个白格子

1. 每行每列只能选一种颜色 —— 证明

结论: 在任意一个独立集中,对每一行 / 每一列:

如果这一行(列)里被选的格子不是空的,那么它们的颜色都相同。

证明:

  • 反设某一行 $x$ 中,在独立集里同时选了一个黑格子 $(x,y_1)$ 和一个白格子 $(x,y_2)$。
  • 按图的定义:只要「同一行且颜色不同」就有一条边。
  • 所以 $(x,y_1)$ 与 $(x,y_2)$ 之间有边。
  • 但独立集中任意两点之间不能有边,矛盾。

同理,对列也是一样。

所以: 最大独立集在原方阵中的形态:每一行 / 每一列中选的格子只会有一种颜色。

这就补上了题解里那句 “形态” 的严谨理由。


四、用集合 $S,T$ 描述独立集

根据上面的结构,我们可以这样编码一个独立集:

  • 对每一行,决定:这行“如果选格子的话”,是选黑还是选白;
  • 对每一列,也做同样的决定。

我们用两个集合来表示“选白”的行列:

  • 集合 $T$:表示选择白色的行
  • 集合 $S$:表示选择白色的列

于是:

  • 行 $x \in T$:这一行里若有选中的格子,则只能选 白格子
  • 行 $x \notin T$:这一行里若有选中的格子,则只能选 黑格子
  • 列 $y \in S$:这一列里若有选中的格子,则只能选 白格子
  • 列 $y \notin S$:这一列里若有选中的格子,则只能选 黑格子

把行和列的选择合在一起,一个格子 $(x,y)$ 能被选,当且仅当:

  • 若它是白色:行、列都选择白:$x \in T, y \in S$;
  • 若它是黑色:行、列都选择黑:$x \notin T, y \notin S$。

我们把这两类格子全部选上,就能得到一个独立集,而且显然是在固定 $(S,T)$ 下数量最多的独立集(因为所有合法格子都选了)。

所以对每一组 $(S,T)$,最大独立集大小就是:

  • 白格子且 $x\in T, y\in S$ 的个数
  • 加上黑格子且 $x\notin T, y\notin S$ 的个数。

题解中对应那句:

对于点 $(x, y)$:

  • 若目前为白且 $x \in T, y \in S$,贡献 $1$;
  • 若目前为黑且 $x \notin T, y \notin S$,贡献 $1$。

至此,“枚举 $S,T$” 这一段就完全合理了。


五、关键观察:行贡献只和 $|S|$ 有关

题解接下来做了一个非常关键的“降维观察”:

  1. 先只枚举列的选择,把“哪些列选白”设为集合 $S$;
  2. 初始先假定“所有行都选白”(即 $T = \{1,\dots,n\}$);
  3. 然后再考虑某些行从“选白”变成“选黑”的收益。

1. 基础方案:所有行选白

设:

  • 每列 $j$ 的白格子数为 $a_j$。

当所有行都选白($T=\{1,\dots,n\}$)时:

  • 对于列 $j\in S$:行、列都选白,所以所有的白格子都可以被选;
  • 对于列 $j\notin S$:列选黑,这里没有格子同时满足“行、列都白”。

于是此时独立集的大小是: $$ \text{Base}(S) = \sum_{j \in S} a_j $$

这就是题解里的那句:

设集合 $S$ 中的列选了白,所有行都选了白。贡献为 $S$ 列中白格子个数。

2. 把某一行从“白行”改为“黑行”的增量贡献

重点:我们在固定 $S$ 的前提下,看某一行改色对答案的影响。

设这一行是第 $i$ 行:

  • 这一行的黑格子数为 $b_i$;
  • 这一行总共 $n$ 个格子。

我们考虑这一行由“选白”(在 $T$ 中)变为“选黑”(不在 $T$ 中)时,独立集大小变化多少。

把这一行里的格子拆成 4 种情况(按颜色 + 所在列是否在 $S$):

  1. 情况 1:白格子,并且所在列在 $S$。

    • 在“行白、列白”时: 行、列都选白 → 这个白格子被选中。
    • 在“行黑、列白”时: 行选黑、列选白 → 白格子不再能被选中。

    这类格子:每个**-1**。

  2. 情况 2:白格子,并且所在列不在 $S$。

    • “行白、列黑”:此时这个白格子不能被选(列选黑);
    • “行黑、列黑”:行也黑了,还是不能选白格子。

    → 这类格子对答案无影响,贡献 0

  3. 情况 3:黑格子,并且所在列在 $S$。

    • “行白、列白”:显然不能选黑格子;
    • “行黑、列白”:依然不能选黑格子(列不是黑)。

    → 这类格子贡献 0

  4. 情况 4:黑格子,并且所在列不在 $S$。

    • “行白、列黑”:行选白,这个黑格子不能选;
    • “行黑、列黑”:行、列都选黑,这个黑格子可以选!

    → 每个贡献 +1

把这四种情况放在一起:

  • 本来被选的:只有情况 1
  • 修改后被选的:只有情况 4

所以这一行净变化 = $$ \text{(情况 4 的个数)} - \text{(情况 1 的个数)} $$

设:

  • 这一行在列 $S$ 中的黑格子数为 $B_S$;
  • 在列 $S$ 中的白格子数为 $W_S$;

则:

  • “情况 1 的个数” = $W_S$;
  • “情况 4 的个数” = 这一行不在 $S$ 中的黑格子数 = 总黑格子数 $b_i$ 减去在 $S$ 中的黑格子数 $B_S$: $$ \text{情况 4 个数} = b_i - B_S $$

于是净贡献: $$ \Delta_i = (b_i - B_S) - W_S = b_i - (B_S + W_S) $$

注意到:

  • 一行里在列 $S$ 中一共有 $|S|$ 个格子;
  • 它们要么是黑要么是白,所以 $B_S + W_S = |S|$。

于是: $$ \boxed{\Delta_i = b_i - |S|} $$

这个式子里已经没有 “$S$ 中哪些具体列” 的信息了,只剩下 $|S|$!

这正是题解中那句 “惊人结论” 的严密证明:

一行从白变黑对答案的贡献是: 行内黑格子数 $b_i$ 减去白列数 $|S|$。 因此贡献和 $S$ 的具体内容无关,只和 $|S|$ 有关。

3. 对整张棋盘的贡献

在固定列集合 $S$ 的前提下:

  • 基础方案(所有行选白)贡献:$\sum_{j\in S} a_j$;
  • 对于每一行 $i$,如果把它从白改黑有正收益 $\Delta_i = b_i-|S|>0$,我们就把这一行改成黑行;否则就保持白行不动。

于是整张图在给定 $S$ 时的最大独立集大小为: $$ \text{MIS}(S) = \sum_{j\in S} a_j + \sum_{i=1}^{n} \max(0, b_i - |S|) $$

设 $|S| = x$,可以写成: $$ \text{MIS}(S) = \sum_{j\in S} a_j + \sum_{i=1}^{n} \max(0, b_i - x) $$

对于固定的 $x$(即固定的 $|S|$),第二项只跟 $x$ 有关,与具体的 $S$ 无关; 第一项要让 $\sum_{j\in S} a_j$ 最大,只要选出“白格子数最多的 $x$ 列”。


六、排序列得到最终公式

记:

  • 对所有列的白格子数 $a_1,\dots,a_n$ 按降序排序,得到 $A_1 \ge A_2 \ge \dots \ge A_n$。

对于给定的 $x = |S|$,最优的列集合是取白格子最多的前 $x$ 列,因此 $$ \max_{|S| = x} \sum_{j\in S} a_j = \sum_{i=1}^{x} A_i $$

于是最大独立集大小可以写成: $$ \text{MIS} = \max_{0 \le x \le n} \left\{ \sum_{i=1}^{n} \max(0, b_i - x) + \sum_{i=1}^{x} A_i \right\} $$

题解里的公式就是这个: $$ \max_{x=0}^n \left\{ \sum_{i=1}^n \max(0, b_i - x) + \sum_{i=1}^x A_i \right\} $$

最后答案(最大匹配)为: $$ \text{Ans} = n^2 - \text{MIS} = n^2 - \max_{0\le x\le n} \left\{ \sum_{i=1}^{n} \max(0, b_i - x) + \sum_{i=1}^{x} A_i \right\} $$

这一步就把“图论 + 结构分析”完整闭环起来了。


七、数据结构那块再解释一下(和代码对应)

题解里后面的“数据结构优化”+ 代码,其核心就是如何维护上面的函数: $$ F(x) = \sum_{i=1}^{n} \max(0, b_i - x) + \sum_{i=1}^{x} A_i $$

并支持单点修改 $a$ / $b$ 后快速更新所有 $x$ 的 $F(x)$ 值的最大值。

1. 静态建初值(对应代码里的 build 部分)

  • 首先用「二维差分 + 一维线段树扫描」做所有矩形翻转,得到初始颜色。

  • 在这个基础上:

    • $a$:每一“列”的白格子数(代码里行列交换了);
    • $b$:每一“行”的黑格子数。
  • 把 $a$ 排序得到 $A$,构造与 $A$ 有关的那一段 $\sum_{i=1}^x A_i$;

  • 利用差分数组 tb 把 $\sum_{i=1}^n \max(0, b_i - x)$ 写成一系列对区间 $[0,n]$ 上的加法,最后得到 tt 线段树叶子上存的就是 $F(x)$ 的值;

  • tt.qrymx() 就得到 $\max_x F(x)$。

上面这些,在前面我们已经从数学上验证过 tb + 区间加的正确性,这里就不重复展开。

2. 修改一个格子时的更新(对应后半段代码)

每次单点翻转 $(r,c)$ 的颜色,会导致:

  • 所在行 / 列某一维度的“白格子数” +1 或 -1;
  • 所在列 / 行另一维度的“黑格子数” +1 或 -1。

在公式里,就是某个 $a_r$ 变为 $a_r \pm 1$,某个 $b_c$ 变为 $b_c \pm 1$。

而:

  • 改 $a_r$:影响排序后的 $A$ 数组中某个元素所在位置的值, 再通过线段树对 一段前缀 / 后缀做区间加减(因为 $\sum_{i=1}^{x} A_i$ 对所有 $x$ 有规律的影响); 代码里用 al[]ar[] 来维护某个“值大小段”在排序后的位置区间。
  • 改 $b_c$:直接在 $F(x)$ 中对所有 $x \le b_c$ 或 $x \le b_c-1$ 做线性变化,也可以被翻译成区间加, 于是同样用线段树实现。

这就是代码中 tt.add(区间, v) 的逻辑来源: 本质就是把对 $a,b$ 的单点变化,转化成对所有 $x$ 上 $F(x)$ 的一段“斜率+截距”变化。

每次改完后,再取一次 tt.qrymx() 就是新的 $\max_x F(x)$,再用 $n^2 - \text{这个值}$ 输出答案。


到这里,题解里的几个“跳得比较快”的点:

  1. 最大匹配 → 最大独立集;
  2. 最大独立集的“行列同色”结构;
  3. 用 $S,T$ 来描述独立集;
  4. 一行从白改黑的增量是 $b_i - |S|$ 且与 $S$ 的具体内容无关;
  5. 排序列得到 $\max_x {\sum \max(0,b_i-x) + \sum_{i\le x} A_i}$;

都已经补上完整的证明和推导了。

评论

0 条讨论

暂时还没有评论,欢迎留下第一条反馈。