FWT 相关做题记录
CF662C Binary Table
有一个暴力思路是:枚举翻转哪些行,然后之后单独考虑翻转列了。如果当前列的 \(1\) 比 \(0\) 多,那么就翻转当前列。复杂度 \(O(2^nnm)\)。
考虑将上面的形式变得更优美,令 \(g(i)=\min(\text{popcount}(i),\text{popcount}(2^n-i))\)。
则答案为 \(\min_{S=0}^{2^n-1} \sum \limits _{i=1}^m g(sta_i\oplus S)\)。其中 \(sta_i\) 表示第 \(i\) 列的状态。考虑把 \(sta_i\) 按照值域分类,\(cnt_i\) 代表 \(sta_j=i\) 的数量。
则写成 \(\min_{S=0}^{2^n-1} \sum \limits _{i=0}^{2^n-1} g(i\oplus S)\times cnt_i\)。令 \(f(i)=\sum \limits _{j\oplus k=i} g(j)\times cnt_{k}\)。则答案为 \(\min \limits_{S=0}^{2^n-1} f(S)\)。使用 FWT 求 \(f\) 数组,复杂度 \(O(n\log n)\)。
P10242 [THUSC 2021] Emiya 家明天的饭
枚举选择的人,那么有 \(\min \limits _{S=0}^{2^n-1} \sum \limits _{i∈S}\sum \limits _{j=1}^m [S⊆T_j]a_{i,j}\)。
先枚举 \(S\),再枚举 \(i\),令 \(g(S,i)=\sum _{j=1}^m [S⊆T_j]a_{i,j}\)。对于每一个 \(i\),将其所有的 \(g(S',i)\) 全部求出来,具体可以用高位前缀和或者 FWT 做。
则答案就为 \(\min \limits _{S=0}^{2^n-1} \sum \limits _{i∈S} g(S,i)\)。
CF850E Random Elections
题目可以看成 \(A\to B,B\to C,A\to C\) 进行比赛。注意到一个人最多赢两场,我们假定 \(A\) 赢两场,分别对战 \(B,C\) 选手。最后将答案乘三即可。
那么就意味着 \(f((A,B)_1,(A,B)_2,\dots,(A,B)_n)=1\) 且 \(f((A,C)_1,(A,C)_2,\dots,(A,C)_n)=1\)。其中 \((A,B)_i\) 表示第 \(i\) 个公民对 \((A,B)\) 的评价。
考虑第 \(i\) 位公民对这两场比赛的的评价为 \(P,Q\):
- 若 \(P=1,Q=1\),则可能的顺序为 \(ABC\) 和 \(ACB\)。
- 若 \(P=1,Q=0\),则可能的顺序为 \(CAB\)。
- 若 \(P=0,Q=1\),则可能的顺序为 \(BAC\)。
- 若 \(P=0,Q=0\),则可能的顺序为 \(BCA\) 和 \(CBA\)。
则存在 \(f(x)=1,f(y)=1\),那么 \(x,y\) 的方案数就为 \(2^{n-pop(x\oplus y)}\)。
那么答案即为 \(\sum\limits _x\sum \limits _y 2^{n-pop(x\oplus y)}\)。可以统计出 \(x\oplus y\) 的值域出现次数,使用 FWT 即可。
P9131 [USACO23FEB] Problem Setting P
把 \(E\) 看成 \(0\),把 \(H\) 看成 \(1\)。记 \(val_x=\sum \limits _{i=1}^{cnt_x} (cnt_x)^{\underline i}\)。
先考虑 \(M=1\) 的情况,方案数为 \(val_0\times val_1\)。
再考虑 \(M\) 更大的情况,因为 \(M\leq 20\),则将所有测试者对第 \(i\) 个问题难度评价压成一个状态 \(s_i\)。假设我们选择的题目依次为 \(a_1,a_2,\dots,a_n\),则要求对于任意 \(1\leq i\leq n-1\) 满足 \(s_{a_i}⊆s_{a_{i+1}}\)。
我们按照值域进行 dp,设 \(f_i\) 表示当前最后一个问题的状态为 \(i\)。那么我们枚举上一个问题,则有方案数 \(1+\sum \limits _{j⊆i} f_j\)。还要乘上当前最后一个问题选择的方案数为 \(val_i\)。故有 \(f_i=val_i\times (1+\sum \limits _{j⊆i} f_j)\)。
直接转移复杂度为 \(O(3^m)\)。考虑分治优化。设当前分治区间为 \([l,r]\),则先递归 \([l,mid]\),再处理 \([l,mid]\) 对 \([mid+1,r]\) 产生的贡献,最后递归 \([mid+1,r]\)。具体的,对 \([l,mid]\) 的 \(f\) 处理出 FWT 即可。复杂度 \(T(n)=2T(\dfrac{n}{2})+n\log n\)。则复杂度为 \(O(2^mm^2)\)。
P7670 [JOI 2018 Final] 毒蛇越狱 / Snake Escaping
记 \(?,0,1\) 的数量分别为 \(a,b,c\) 个。
考虑如果 \(?\) 的数量比较少,那么可以暴力枚举 \(O(2^a)\) 计算。
如果 \(0\) 的数量比较小,那么我们可以容斥计算,将 \(0\) 换成 \(1\) 或者 \(?\)。比如 \(res_{001???}=res_{??1???}-res_{?11???}-res_{1?1???}+res_{111???}\)。注意到如果只有 \(1\) 或者 \(?\) 的时候,可以使用高维前缀和计算超集。复杂度 \(O(2^b)\)。
如果 \(1\) 的数量比较小,同理可以容斥计算,将 \(1\) 换成 \(0\) 或 \(?\)。只有 \(0\) 和 \(?\) 的时候,可以把 \(?\) 看成 \(1\) 去计算子集。复杂度 \(O(2^c)\)。
则总复杂度 \(O(T\min(2^a,2^b,2^c))=O(T2^{\lfloor\frac{n}{3}\rfloor})\)。
P4221 [WC2018] 州区划分
考虑状压。定义 \(f_i\) 表示状态为 \(i\) 的城市划分的价值总和。定义 \(g_i\) 表示状态为 \(i\) 的城市能否构成一个州,这个可以在 \(O(2^nn^2)\) 时间复杂度内处理出来。
转移有 \(f_i=\sum \limits _{S\subset i} f_S\times g_{i-S}\times \dfrac{sum_S}{sum_i}\)。其中 \(sum_i\) 表示集合 \(i\) 内城市人口总和。转化一下变成 \(f_i=\dfrac{1}{sum_i}\sum \limits _{S\subset i} f_S\times g_{i-S}\times sum_S\)。枚举子集做可以做到 \(O(3^n)\)。
观察形式 \(i\) 和 \(i-S\),可以写成两个数 \(a,b\) 或起来等于 \(i\),但与起来等于 \(0\)。两个数 \(a,b\) 或起来等于 \(i\) 可以用 FWT 刻画,但与起来等于 \(0\) 不好操作。但我们加一个条件,\(|a|+|b|=|i|\),\(|x|\) 代表二进制中一的数量,则可以完美刻画。
对于本题我们换一个转移顺序,因为 \(|S|<|i|\),则我们可以按照二进制中 \(1\) 的数量从小到大枚举 \(i\),转移时暴力枚举 \(|S|\) 的值,将满足 \(|a|=|S|\) 的 \(f_a\) 和 \(|b|=|i|-|S|\) 的 \(g_b\) 卷在一起即可。复杂度 \(O(2^nn^2)\)。
这个套路叫做子集卷积。

浙公网安备 33010602011771号