【算法竞赛】线性基

4 minute read

问题导入

给定一个图。求一条回路使得该路径的异或和最大。

线性基

线性基的构造

对于一个数集 $S$,我们可以用以下代码构造一组线性基 $D$。

 1for(int i = 1; i <= cnt; ++i) {
 2        LL cur = S[i];
 3        for(int k = 59; k >= 0; --k) {
 4            if(cur & (1ll << k)) {
 5                if(d[k]) cur ^= d[k];
 6                else {
 7                    d[k] = cur;
 8                    break;
 9                }
10            }
11        }
12    }

线性基的性质及略证

如此构建后,线性基中的所有数满足如下性质。

  1. 若 $d_i$ 非零:$d_i$ 在第 $i$ 位是 $1$,这也是它的最高位。这也意味着:对于所有比它小的 $d_j$,其第 $i$ 位必为零。 若 $d_i$ 为零:………… 那它就是零呗。

  2. 数集 $S$ 中的任意数将可以被 $D$ 中的若干数唯一异或表示。

  3. $D$ 中的任意数将可以被 $S$ 中的若干数异或表示。

  4. 选择 $D$ 中的若干数进行异或和,结果不可能为 $0$。

  5. 不存在一个长度更小的数集 $D$,满足上述性质。

性质 1 的证明提示:由上述代码可见,一个数要么在经过若干次异或后进入线性基,要么经过若干次异或后变为 $0$。“唯一”可由性质 3 推导而来。

性质 2 的证明提示:考虑数学归纳。线性基中最大的数一定属于 $S$;次大的数要么属于 $S$,要么由某个属于 $S$ 中的数和最大的数经过一次异或后得来……

性质 3 的证明提示:选择出的数一定有一个最大的数。这个最大的数的最高二进制位可以证明只有它自己为 $1$,其他的选择出的数该位全为 $0$。

性质 4 的证明提示:考虑削减一个 $D$ 中的数 $x$。假设 $x$ 由 $S$ 中的数 $v$ 经过若干次异或插入进线性基,这意味着 $v$ 可以由 包括 $x$ 在内的 若干 $D$ 中的数异或表示。若存在一个长度更小的数集 $D$,满足上述性质,那么意味着 $v$ 可以由 不包括 $x$ 在内的 若干 $D$ 中的数异或表示。这与性质 1 矛盾。假设不成立,性质 4 成立。

解最大异或和

由于性质 0,我们可以直接贪心地找最大异或和。

从高位往低位扫描,时刻记录一个 ans。若 ans 的第 $i$ 位为 $0$,则异或上一个 $d_i$。否则不异或 $d_i$。

你可能会觉得——这样最大异或和不总是 11111…11 吗?事实上,不是所有的 $d_i$ 都非零哦。

引入问题的解

随便找一棵 dfs 树,通过返祖边或者横插边构成若干个基本环。可以证明,所有的环均可以由基本环异或表示。

将基本环的异或和丢进线性基,找最大异或和即可。