1 条题解
-
0
自动搬运
来自洛谷,原作者为

xht
好想爱这个世界啊搬运于
2025-08-24 22:02:55,当前版本为作者最后更新于2019-12-11 03:10:04,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
请在博客中查看
核心思想
记对序列 进行快速沃尔什变换后的序列为 。
已知序列 ,求一个新序列 ,直接计算是 的。
若 和 是 的,而 是 的,同时 也是 的。
那么我们可以利用上述过程 求出 。
OI 中的运用
在 OI 中,FWT 是用于解决对下标进行位运算卷积问题的方法。
其中 是二元位运算中的一种。
或
要求
显然有 。
构造 。
则有
$$\begin{aligned} fwt[a] \times fwt[b] &= \left(\sum_{j|i=i} a_j\right)\left(\sum_{k|i=i} b_k\right) \\\\ &= \sum_{j|i=i} \sum_{k|i=i} a_jb_k \\\\ &= \sum_{(j|k)|i = i} a_jb_k \\\\ &= fwt[c] \end{aligned} $$要求
令 表示 中下标最高位为 的那部分序列, 表示 中下标最高位为 的那部分序列。
则有
$$fwt[a] = \text{merge}(fwt[a_0], fwt[a_0] + fwt[a_1]) $$其中 表示「拼接」, 表示对应位置相加。
于是可以分治。
inline void OR(modint *f) { for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) for (int i = 0; i < n; i += o) for (int j = 0; j < k; j++) f[i+j+k] += f[i+j]; }由
$$fwt[a] = \text{merge}(fwt[a_0], fwt[a_0] + fwt[a_1]) $$可得
inline void IOR(modint *f) { for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) for (int i = 0; i < n; i += o) for (int j = 0; j < k; j++) f[i+j+k] -= f[i+j]; }显然两份代码可以合并。
inline void OR(modint *f, modint x = 1) { for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) for (int i = 0; i < n; i += o) for (int j = 0; j < k; j++) f[i+j+k] += f[i+j] * x; }与
同理或。
inline void AND(modint *f, modint x = 1) { for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) for (int i = 0; i < n; i += o) for (int j = 0; j < k; j++) f[i+j] += f[i+j+k] * x; }异或
定义 ,其中 表示「二进制下 的个数」。
满足 $(i \otimes j) \operatorname{xor} (i \otimes k) = i \otimes (j \operatorname{xor} k)$。
构造 $fwt[a]_i = \sum_{i\otimes j = 0} a_j - \sum_{i\otimes j = 1} a_j$。
则有
$$\begin{aligned} fwt[a] \times fwt[b] &= \left(\sum_{i\otimes j = 0} a_j - \sum_{i\otimes j = 1} a_j\right)\left(\sum_{i\otimes k = 0} b_k - \sum_{i\otimes k = 1} b_k\right) \\ &=\left(\sum_{i\otimes j=0}a_j\right)\left(\sum_{i\otimes k=0}b_k\right)-\left(\sum_{i\otimes j=0}a_j\right)\left(\sum_{i\otimes k=1}b_k\right)-\left(\sum_{i\otimes j=1}a_j\right)\left(\sum_{i\otimes k=0}b_k\right)+\left(\sum_{i\otimes j=1}a_j\right)\left(\sum_{i\otimes k=1}b_k\right) \\ &=\sum_{i\otimes(j \operatorname{xor} k)=0}a_jb_k-\sum_{i\otimes(j\operatorname{xor} k)=1}a_jb_k \\ &= fwt[c] \end{aligned} $$因此
$$\begin{aligned} fwt[a] &= \text{merge}(fwt[a_0] + fwt[a_1], fwt[a_0] - fwt[a_1]) \\\\ a &= \text{merge}(\frac{a_0 + a_1}2, \frac{a_0 - a_1}2) \end{aligned} $$inline void XOR(modint *f, modint x = 1) { for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) for (int i = 0; i < n; i += o) for (int j = 0; j < k; j++) f[i+j] += f[i+j+k], f[i+j+k] = f[i+j] - f[i+j+k] - f[i+j+k], f[i+j] *= x, f[i+j+k] *= x; }【模板】P4717 【模板】快速沃尔什变换
const int N = 1 << 17 | 1; int n, m; modint A[N], B[N], a[N], b[N]; inline void in() { for (int i = 0; i < n; i++) a[i] = A[i], b[i] = B[i]; } inline void get() { for (int i = 0; i < n; i++) a[i] *= b[i]; } inline void out() { for (int i = 0; i < n; i++) print(a[i], " \n"[i==n-1]); } inline void OR(modint *f, modint x = 1) { for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) for (int i = 0; i < n; i += o) for (int j = 0; j < k; j++) f[i+j+k] += f[i+j] * x; } inline void AND(modint *f, modint x = 1) { for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) for (int i = 0; i < n; i += o) for (int j = 0; j < k; j++) f[i+j] += f[i+j+k] * x; } inline void XOR(modint *f, modint x = 1) { for (int o = 2, k = 1; o <= n; o <<= 1, k <<= 1) for (int i = 0; i < n; i += o) for (int j = 0; j < k; j++) f[i+j] += f[i+j+k], f[i+j+k] = f[i+j] - f[i+j+k] - f[i+j+k], f[i+j] *= x, f[i+j+k] *= x; } int main() { rd(m), n = 1 << m; for (int i = 0; i < n; i++) rd(A[i]); for (int i = 0; i < n; i++) rd(B[i]); in(), OR(a), OR(b), get(), OR(a, P - 1), out(); in(), AND(a), AND(b), get(), AND(a, P - 1), out(); in(), XOR(a), XOR(b), get(), XOR(a, (modint)1 / 2), out(); return 0; }
- 1
信息
- ID
- 3694
- 时间
- 1000ms
- 内存
- 250MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者