闲话 23.1.13

闲话

计算几何怎么学?

今日推歌:《GravityRain》by てぃあら feat. 初音ミク
冷门良曲!很推荐听一听的!

昨天闲话怎么没人看啊??
引流!!!

\(\text{FWT}\)

发现这个知识点还没补,所以补上。

对照加卷积在幂级数上的贡献方式,我们定义位运算卷积对幂级数的贡献方式。假设 \(A,B\) 是两个幂级数,两者的位运算卷积满足 \(A[i]\times B[j]\)\(i\oplus j\) 有贡献,其中 \(\oplus\) 为一种特定的位运算。形式化地,若 \(A, B\) 对位运算 \(\oplus\) 的卷积记作 \(A\oplus B\),则该运算产生的 \(S = A\oplus B\) 满足

\[S[n] = \sum_{i\oplus j = n} A[i]B[j] \]

对照 \(\text{DFT}\) 的做法,我们发现 \(\text{DFT}\) 把系数转成了点值后卷积操作变成了直接乘。我们也希望通过将系数转化后使位运算卷积变成乘法。
我们设 \(\text{FWT}(A)\) 是对幂级数 \(A\) 经过 \(\text{FWT}\) 变换后得到的幂级数,则我们需要满足

\[A\oplus B = S \Longleftrightarrow \text{FWT}(S)[n] = \text{FWT}(A)[n]\times \text{FWT}(B)[n] \]

对照 \(\text{DFT}\) 的性质,我们希望 \(\text{FWT}\) 也是一个线性变换。不妨设 \(A[j]\)\(\text{FWT}(A)[i]\) 的贡献系数为 \(c(i, j)\),我们能确定

\[\text{FWT}(A)[i] = \sum_{j=0}^{n - 1} c(i, j) A[j] \]

我们考虑 \(\text{FWT}\) 的性质,得到

\[\begin{aligned} \text{FWT}(A)[k]\times \text{FWT}(B)[k] &= \text{FWT}(C)[k] \\ \sum_{i=0}^{n - 1} c(k, i) A[i] \times \sum_{i=0}^{n - 1} c(k, i) B[i] &= \sum_{i=0}^{n - 1} c(k, i) C[i] \\ \sum_{i=0}^{n - 1}\sum_{j=0}^{n - 1} c(k, i) c(k, j) A[i] B[j] &= \sum_{i=0}^{n - 1} c(k, i) C[i] \\ \end{aligned}\]

同时由于 \(A\oplus B = C\),有

\[\begin{aligned} C[k] &= \sum_{i\oplus j = k} A[i]B[j] \\ \sum_{k=0}^{n - 1} c(m, k) C[k] &= \sum_{k=0}^{n - 1} c(m, k) \sum_{i\oplus j = k} A[i]B[j] \\ \sum_{i=0}^{n - 1}\sum_{j=0}^{n - 1} c(m, i) c(m, j) A[i] B[j] &= \sum_{k=0}^{n - 1} c(m, k) \sum_{i\oplus j = k} A[i]B[j] \\ \sum_{i=0}^{n - 1}\sum_{j=0}^{n - 1} c(m, i) c(m, j) A[i] B[j] &= \sum_{k=0}^{n - 1} \sum_{i\oplus j = k} c(m, i\oplus j) A[i]B[j] \\ \sum_{i=0}^{n - 1}\sum_{j=0}^{n - 1} c(m, i) c(m, j) A[i] B[j] &= \sum_{i=0}^{n - 1}\sum_{j=0}^{n - 1} c(m, i\oplus j) A[i]B[j] \\ \end{aligned}\]

对比系数得到 \(c(m, i)c(m, j) = c(m, i \oplus j)\)。发现 \(c\) 第二维可以由位运算决定,因此我们可以分位构造。具体地,我们可以得到 \(c(i, j)\)\(i, j\in \{0, 1\}\) 的四种取值后计算每个 \(c(n, m)\)。记一个数字 \(a\) 二进制表示的第 \(i\) 位为 \(a_i\),则我们能得到

\[c(i, j) = \prod_{b} c(i_b, j_b) \]

容易发现这对每一位是满足需要的,因此这式子肯定满足一种构造下的 \(c\) 函数。因此 \(\text{FWT}\) 的关键在于写出 \(c(i, j)\)\(i, j\in \{0, 1\}\) 的四种取值,随后构造矩阵描述线性变换。

我们写出 \(\text{FWT}\) 的式子:

\[\text{FWT}(A)[i] = \sum_{j=0}^{n - 1} c(i, j) A[j] \]

随后可以折半。我们设 \(i\) 去掉最高位得到 \(i'\),则有

\[\begin{aligned} \text{FWT}(A)[i] &= \sum_{j=0}^{n - 1} c(i, j) A[j] \\ &= c(i_0, 0) \sum_{j=0}^{(n / 2) - 1} c(i', j') A[j] + c(i_0, 1) \sum_{j=n / 2}^{n - 1} c(i', j') A[j] \end{aligned}\]

可以发现这就是折半的过程。这启发我们通过低 \(n / 2\) 位和高 \(n / 2\) 位分别地描述 \(\text{FWT}\)。假设幂级数 \(A\) 的低 \(n/2\) 次项组成 \(A_0\),高 \(n/2\) 次项组成 \(A_1\),则我们可以发现,对于 \(i\in [0, n / 2)\)

\[\begin{aligned} \text{FWT}(A)[i] &= c(0, 0)\text{FWT}(A_0)[i] + c(0, 1) \text{FWT}(A_1)[i] \\ \text{FWT}(A)[n / 2 + i] &= c(1, 0)\text{FWT}(A_0)[i] + c(1, 1) \text{FWT}(A_1)[i] \end{aligned}\]

这也就导出了所构造的矩阵。随后我们就能以 \(O(n)\) 的复杂度合并两个规模为 \(n/2\) 的子问题了。若 \(n = 2^k\),则总时间复杂度为 \(O(k2^k)\)。可以暴力模拟矩阵合并。
对应的 \(\text{IFWT}\) 也不难想象了,就是做矩阵求逆的过程。这隐式地要求下面的矩阵必须有逆,也就是满秩。

随后我们的问题就是根据不同的运算构造矩阵了。记要构造的矩阵

\[c = \begin{bmatrix}c(0, 0) & c(0, 1) \\ c(1, 0) & c(1, 1) \end{bmatrix} \]

\(\text{or}\)

我们可以分别讨论:

  1. \(c(0, 0) c(0, 0) = c(0, 0|0) = c(0, 0)\)
    \(c(0, 0) = 0/1\)
  2. \(c(0, 1) c(0, 0) = c(0, 1|0) = c(0, 1)\)
    \(c(0, 1) = 0\)\(c(0, 0) = c(0, 1) = 1\)
  3. \(c(1, 1) c(1, 0) = c(1, 1 | 0) = c(1, 1)\)
    \(c(1, 1) = 0\)\(c(1, 1) = c(1, 0) = 1\)

我们可以得到两种矩阵:\(\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}\)\(\begin{bmatrix} 1 & 0 \\ 1 & 1 \end{bmatrix}\)。第二个矩阵和子集和是同构的,因此有时 SOSDP 会采用 \(\text{FWT}\) 优化合并。你问为啥?这是由于第二个矩阵描述了 \(c(i, j) = [i \text{ and } j = j]\),这在分位构造后就是 \(n\text{ and } m = m\),附一个状压意义就得到了 \(m \in n\)

\[\begin{bmatrix} 1 & 0 \\ 1 & 1 \end{bmatrix}^{-1} = \begin{bmatrix} 1 & 0 \\ -1 & 1 \end{bmatrix} \]

\(\text{and}\)

仍然是分别讨论:

  1. \(c(0, 1) c(0, 0) = c(0, 1\&0) = c(0, 0)\)
    \(c(0, 0) = 0\)\(c(0, 0) = c(0, 1) = 1\)
  2. \(c(1, 1) c(1, 0) = c(1, 1 \& 0) = c(1, 0)\)
    \(c(1, 0) = 0\)\(c(1, 1) = c(1, 0) = 1\)
  3. \(c(1, 1) c(1, 1) = c(1, 1 \& 1) = c(1, 1)\)
    \(c(1, 1) = 0/1\)

这也能构造出两种矩阵:\(\begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}\)\(\begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix}\)。和上面的是转置的结果。

\[\begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix}^{-1} = \begin{bmatrix} 1 & -1 \\ 0 & 1 \end{bmatrix} \]

\(\text{xor}\)

记异或为 \(\oplus\)。仍然是分别讨论:

  1. \(c(0, 0) c(i, j) = c(i, j\oplus 0) = c(i, j)\)
    \(c(0, 0) = 1\)
  2. \(c(1, 1) c(1, 1) = c(1, 1 \oplus 1) = c(1, 0)\)
    这里 \(c(1, 1)\)\(c(1, 0)\) 必须均非 \(0\)
  3. \(c(1, 1) c(1, 0) = c(1, 1 \oplus 0) = c(1, 1)\)
    \(c(1, 0) = 1\)
  4. \(c(0, 1) c(0, 1) = c(0, 1 \oplus 1) = c(0, 0) = 1\)
    \(c(0, 1) = 1 / -1\)

这也能构造出两种矩阵:\(\begin{bmatrix} 1 & 1 \\ -1 & 1 \end{bmatrix}\)\(\begin{bmatrix} 1 & 1 \\ 1 & -1 \end{bmatrix}\)

\[\begin{bmatrix} 1 & 1 \\ 1 & -1 \end{bmatrix}^{-1} = \begin{bmatrix} 1/2 & 1/2 \\ 1/2 & -1/2 \end{bmatrix} \]

这也是为什么对异或的 \(\text{IFWT}\) 需要除以 \(2\)

直接通过矩阵乘法是可以实现的,cmd 的提交记录

最后放出板子代码。可以看出,我们构造的 \(\text{FWT}\)\(\text{FFT}\) 是基本同构的。

code
inline void OR(int f[], int len, int typ) {
	if (typ != 1) typ = mod - 1;
    for (int mid = 1; mid < len; mid <<= 1) 
        for (int i = 0, j = 0; j < len; j += (mid << 1)) 
            for (int k = 0; k < mid; ++ k) 
                f[j + k + mid] = (f[j + k + mid] + 1ll * f[j + k] * typ) % mod;
}


inline void AND(int f[], int len, int typ) {
	if (typ != 1) typ = mod - 1;
    for (int mid = 1; mid < len; mid <<= 1) 
        for (int j = 0; j < len; j += (mid << 1)) 
            for (int k = 0; k < mid; ++ k) 
                f[j + k] = (f[j + k] + 1ll * f[j + k + mid] * typ) % mod;
}

inline void XOR(int f[], int len, int typ) {
	if (typ != 1) typ = (mod + 1) / 2;
    for (int mid = 1, t; mid < len; mid <<= 1) 
        for (int j = 0; j < len; j += (mid << 1)) 
            for (int k = 0; k < mid; ++ k) 
				t = f[j + k + mid],
				f[j + k + mid] = 1ll * typ * (f[j + k] - f[j + k + mid] + mod) % mod,
				f[j + k] = 1ll * typ * (f[j + k] + t) % mod;
}

同样可以直接构造并观察性质,但这在推导 \(\text{xor}\) 时会较麻烦。

参考资料:
位运算卷积(FWT) & 集合幂级数, command_block

posted @ 2023-01-13 21:27  joke3579  阅读(73)  评论(1编辑  收藏  举报