一些东西

FWT 和线性基和集合幂级数

下文中 \(\&\) 表示与运算,\(|\) 表示或运算。
感觉我写的很乱(?
集合幂级数
其实就是指数上是 \(\mathbb{F}_2^{n}\) 下的向量,一般看成一个二进制数。
对于两个 \(\mathbb{F}_2^n\) 下的向量 \(u,v\),定义它们的加法是按位做不进位加法,也就是异或,它们的内积等于 \(\text{popcount}(u\&v)\bmod 2\),若内积等于 \(0\) 则它们正交。
内积运算满足分配律。
下面的向量默认是在 \(\mathbb{F}_2^n\) 下的。
线性基
一组线性基 \(B\) 是若干个线性无关的向量,用 \(\text{span}(B)\) 表示 \(B\) 长成的空间。
有些时候要让线性基中每个元素的最高位独立,可以做个高斯消元。
对于一组秩为 \(k\) 的线性基 \(A\),定义它的正交线性基 \(A^{\perp}\) 满足 \(\text{span}(A^{\perp})\)\(\text{span}(A)\) 的正交补空间,由维数定理可知 \(A^{\perp}\) 的秩为 \(n-k\)
image
这是一个很抽象的正交线性基(?其中绿色那两行是属于 \(A^{\perp}\) 的,其它行是 \(A\) 的。
对与 \(A\) 的第 \(i\) 行,它的最高位为 \(i\),称为关键位,为了构造出正交线性基,得先让 \(A\) 的关键位独立,也就是只有那一行的第 \(i\) 位为 \(1\),这个直接高斯消元就行。
然后把 \(A\) 缺的那几行补到 \(A^{\perp}\) 里,其中 \(A^{\perp}\) 的第 \(i\) 行的最低位为 \(i\),对于第 \(i\) 行的第 \(j\) 位,\(j>i\),满足 \(A^{\perp}_{i,j}=A_{j,i}\),也就是一个转置。
FWT
考虑如下问题:有两个集合幂级数 \(a_0,\ldots,a_{n-1}\)\(b_{0},\ldots,b_{n-1}\),需要求出一个集合幂级数 \(c_0,\ldots,c_{n-1}\),使得:

\[c_i=\sum_{j\oplus k=i}a_jb_k \]

\(\oplus\) 表示或运算。
可以思考一个类似 FFT 的东西,先对 \(a\)\(b\) 都做一个线性变换,然后点乘起来,最后做个逆运算就是 \(c\)。这个就是 FWT,逆运算叫做 IFWT。
\(A=[a_0,\ldots,a_{n-1}]^{T}\),可以构造一个矩阵 \(M\),线性变换就是左乘上 \(M\),当然这个矩阵要求可逆。
\(M\times A=[\hat{a}_0,\ldots,\hat{a}_{n-1}]^T\),则 \(\hat{a}_i=\sum_{j=0}^{n-1}M_{i,j}\times a_j\)\(\hat{b}\)\(\hat{c}\) 同理,所以:

\[\begin{aligned}\hat{a}_i\hat{b}_i&=\hat{c}_i\\ (\sum_{j=0}^{n-1}M_{i,j}\times a_j)\times(\sum_{j=0}^{n-1}M_{i,j}\times b_j)&=\sum_{j=0}^{n-1}M_{i,j}\times c_j\\ \sum_{j=0}^{n-1}\sum_{k=0}^{n-1}M_{i,j}M_{i,k}a_jb_k&=\sum_{j=0}^{n-1}M_{i,j}\times(\sum_{k\oplus l=j}a_kb_l)\\ \sum_{j=0}^{n-1}\sum_{k=0}^{n-1}M_{i,j}M_{i,k}a_jb_k&=\sum_{j=0}^{n-1}\sum_{k=0}^{n-1}M_{i,j\oplus k}a_jb_k\\ M_{i,j}M_{i,k}&=M_{i,j\oplus k} \end{aligned}\]

不难构造出 \(M_{i,j}=[i\oplus j=i]\),显然 \(\hat{a}_i=\sum_{j\oplus i=i}a_j,M^{-1}_{i,j}=\left\{\begin{matrix} (-1)^{\text{popcount}(i)+\text{popcount}(j)}&i\oplus j=i\\ 0&\text{otherwise} \end{matrix}\right.\)
但你显然不能直接乘,因为是 \(O(n^2)=O(4^m)\) 的,寄!可以构造一个 \(2\times 2\) 的矩阵使得 \(M_{i,j}=\prod_{k=0}^{m-1}w_{v_k(i),v_k(j)}\)\(v_k(i)\) 表示二进制下 \(i\) 的第 \(k\) 位,最低位是 \(0\)
不难得到 \(M\) 对应的 \(w\)\(\begin{bmatrix}1&0\\1&1\end{bmatrix}\)\(M^{-1}\) 对应的 \(w'\) 就是 \(w\) 的逆矩阵 \(=\begin{bmatrix}1&0\\-1&1\end{bmatrix}\)
那么这有什么用呢。注意到 \(\hat{a}_i=\sum_{j=0}^{n-1}a_j\prod_{k=0}^{m-1}w_{v_k(i),v_k(j)}\),而每一位是独立的,所以可以设 \(s_{i,j}=\sum_{k}a_k\prod_{l=0}^{i-1}w_{v_k(j),v_k(k)}\)\(k\) 是所有第 \(i\)\(m\) 位和 \(j\) 相同的数,初始 \(s_0=a\),转移就是 \(s_{i,j}=s_{i-1,j}\times w_{0,0}+s_{i-1,j+2^{i}}\times w_{0,1},s_{i,j+2^i}=s_{i-1,j}\times w_{1,0}+s_{i-1,j+2^i}\times w_{1,1}\),其中 \(v_i(j)=0\)。复杂度为 \(O(m2^m)\)
同理,当 \(\oplus\) 表示与运算时,有 \(w=\begin{bmatrix}1&1\\0&1\end{bmatrix},w^{-1}=\begin{bmatrix}1&-1\\0&1\end{bmatrix}\)
\(\oplus\) 表示异或运算时,直接构造 \(M_{i,j}=[i\oplus j=i]\) 是不行的,注意到 \((-1)^{\text{popcount}(i)+\text{popcount}(j)}=(-1)^{\text{popcount}(i\oplus j)}\),所以 \(w=\begin{bmatrix}1&1\\1&-1\end{bmatrix},w^{-1}=\begin{bmatrix}\frac{1}{2}&\frac{1}{2}\\\frac{1}{2}&-\frac{1}{2}\end{bmatrix}\)。如果你善于观察会发现在 XOR 情况下 \(\text{IFWT}(a)_i=\frac{1}{n}\text{FWT}(a)_i\)
不过 \(M_{i,j}M_{i,k}=M_{i,j\oplus k}\) 好像有些时候是寄掉的,可以学习 https://www.luogu.com.cn/article/76llxu54
对于一些组合意义:
考虑 OR FWT,即 \(\hat{a}_i=\sum_{j|i=i}a_j\),你发现它本质上高维前缀和,AND FWT 就是高维后缀和。
考虑 XOR FWT,根据上面可以得到 \(M_{i,j}=(-1)^{\text{popcount}(i\&j)},\hat{a}_i=\sum_{j=0}^{n-1}(-1)^{\text{popcount}(i\&j)}a_j\),本质上是与 \(i\) 正交的向量的权值和减去不与 \(i\) 正交的向量的权值和。
XOR FWT 与正交线性基
对于一组集合幂级数 \(F=\sum_{i}f_ix^i\) 和一个秩为 \(k\) 的线性基 \(A\)\(F\) 满足若 \(u\in\text{span}(A)\)\(f_u=1\),否则 \(f_u=0\)
\(F\) 做一次 XOR FWT 后为 \(\hat{F}=\sum_{i}\hat{f}_ix^i\),有结论是 \(\hat{f}_i\in\{0,2^k\}\)
为什么呢?考虑 \((F*F)_u\) 的意义是在 \(\text{span}(A)\) 中选两个向量 \(v,w\) 使得 \(v+w=u\) 的对数,显然 \(\text{span}(A)\) 中的加法是封闭的,所以 \(F*F=F\cdot 2^k\),两边都做一个 \(\text{FWT}\)\(\hat{F}\times \hat{F}=\hat{F}\cdot 2^k\),因此 \(\hat{f}_i\in\{0,2^k\}\)。上面的 \(*\) 为卷积,\(\times\) 为点乘。
\(\hat{f}_i=2^k\)\(i\) 构成 \(\text{span}(A^{\perp})\)
为什么呢?根据 \(\text{FWT}\) 显然有 \(\hat{f}_u=\sum_{v\in\text{span}(A)}(-1)^{u\cdot v}\),若 \(\hat{f}_u=2^k\)\(u\)\(\text{span}(A)\) 中的所有向量正交,符合定义。
你发现 \(\min(\text{rank}(A),\text{rank}(A^{\perp}))\le\frac{n}{2}\),就能做一些很好的事情。
子集卷积
考虑如下问题:有两个集合幂级数 \(a_0,\ldots,a_{2^n-1}\)\(b_{0},\ldots,b_{2^n-1}\),需要求出一个集合幂级数 \(c_0,\ldots,c_{2^n-1}\),使得:

\[c_i=\sum_{j|k=i,j\& k=0}a_jb_k \]

你发现 \(j\&k=0\) 当且仅当 \(\text{popcount}(j)+\text{popcount}(k)=\text{popcount(j|k)}=\text{popcount(i)}\)
所以可以把 \(a_i\)\(\hat{a}_i\) 都变成一个占位多项式 \(a_i(x)=a_ix^{\text{popcount}(i)},\hat{a}_i(x)=\sum_{j=0}^{m=1}(\sum_{k\mid i=i,\text{popcount}(k)=j}a_k)x^j\)\(b_i,\hat{b}_i,c_i,\hat{c}_i\) 同理。
你发现 \(\hat{c}_i(x)=\hat{a}_i(x)\hat{b}_i(x)\),求 \(\hat{a}_i(x),\hat{b}_i(x)\) 就是对每个 \(j\) 做一次 FWT,\(c_i\) 是做 IFWT。
时间复杂度是 \(O(n^22^n)\)
集合幂级数 \(\text{exp}\)
追忆(学习)一下形式幂级数的 \(\text{exp}\)\(\text{exp}(f(x))=\sum_{i\ge 0}\frac{f^i(x)}{i!}\),记为 \(g(x)\)。设 \(f(x)=\sum_{i\ge 0}\frac{f_i}{i!}x^i,g(x)=\sum_{i\ge 0}\frac{g_i}{i!}x^i,f'_i=i!f_i,g'_i=i!g_i\)

\[\begin{aligned}g(x)&=\text{exp}(f(x))\\ g'(x)&=f'(x)\text{exp}(f(x))\\ g'(x)&=f'(x)g(x)\\ \sum_{i\ge 0}(i+1)g'_{i+1}x^i&=(\sum_{i\ge 0}(i+1)f'_{i+1}x^i)\times(\sum_{i\ge0}g'_ix^i)\\ (n+1)g'_{n+1}&=\sum_{i=0}^{n}(i+1)f'_{i+1}g'_{n-i}\\ n\times g'_n&=\sum_{i=1}^{n}i\times f'_i\times g'_{n-i}\\ \frac{g_n}{(n-1)!}&=\sum_{i=1}^{n}\frac{f_i}{(i-1)!}\times\frac{g_{n-i}}{(n-i)!}\\ g_n&=\sum_{i=1}^{n}\binom{n-1}{i-1}f_ig_{n-i}\\ g_n&=\sum_{S_i\cap S_j=\varnothing,\bigcup S=\{1,\ldots,n\}}\prod_{i=1}^{k}f_{|S_i|} \end{aligned}\]

注意一下,最后那个式子里的那个集合序列是无序的。
所以说,EGF 的 \(\text{exp}\) 的组合意义就是,把大小为 \(n\) 的集合无序地划分成若干个集合,所有划分方案的集合的权值积的和。当然 \(f_0=0\),不然会爆炸。
那么什么是集合幂级数 \(\text{exp}\) 呢?
给你一个集合幂级数 \(F(x)=\sum_{S}f_Sx^S\),需要对每个 \(S\subseteq\{1,\ldots,n\}\) 求出 \(g_S=\sum_{S_i\cap S_j=\varnothing,\bigcup S_i=S}\prod_{i=1}^{k}f_{S_i}\),保证 \(f_{\varnothing}=0\)
显然 \(g_{\varnothing}=1\)。设 \(t=\max_{x\in S}x\),考虑枚举 \(t\) 所在的集合 \(T\),于是就有 \(g_S=\sum_{t\in T,T\subset S}f_T\times g_{S\backslash T}\)。直接做是 \(O(3^n)\) 的。
注意到 \(T\cap S\backslash T=\varnothing\),唉!这不是我们子集卷积吗,直接做 \(n\) 次子集卷积,复杂度是 \(O(n^22^n)\)(并非 \(O(n^32^n)\))。
集合幂级数 \(\ln\)
根据上文可以知道 \(\text{exp}\) 的组合意义是所有划分方案的集合的权值积的和,而 \(\ln\)\(\text{exp}\) 的逆运算,所以 \(\ln\) 的组合意义就是划分成一个集合的权值。
式子就是 \(g_S=f_S-\sum_{t\in T,T\subset S}g_T\times f_{S\backslash T}\),本质上是容斥掉划分为多个集合的情况。
集合幂级数求逆
\(G(x)\)\(F(x)\) 的逆,则 \(F(x)G(x)=1\),也就是 \(\sum_{T\subseteq S}f_T\times g_{S\backslash T}=[S=\varnothing]\)
显然 \(g_{\varnothing}=\frac{1}{f_{\varnothing}}\)\(g_S=-\sum_{T\subset S}g_T\times f_{S\backslash T}(S\ne\varnothing)\)

wqs 二分

考虑一个问题:
有若干个物品,要恰好选出 \(m\) 个物品,且价值最大。
\(f(x)\) 为恰好选出 \(x\) 个物品的最大价值,它是个凸的东西。
image
假设它是个上凸包。
image
用若干条斜率为 \(k\) 的直线去穿过这些点,截距就是 \(f(x)-xk\)
考虑求出使这个东西最大的 \(x'\),虽然我不知道怎么求。
你发现,如果这个 \(x'<m\),因为斜率是不减的,所以可以让 \(k\) 小一点,直到 \(x'=m\),类似的有 \(x'>m\) 时让 \(k\) 变大。
求出答案后应该加上 \(mk\)

q-analog

定义一个自然数 \(n\)\(q\)-模拟为 \([n]_q=\sum_{i=0}^{n-1}q^i\),可以看作一个关于 \(q\) 的多项式。
定义 \(q\)-阶乘为 \([n]_q!=\prod_{i=1}^{n}[i]_q,[0]_q!=1\)
设对于一个长为 \(n\) 的排列 \(p\),定义它的逆序对数为 \(\text{inv}(p)\),那么 \(q\)-阶乘的组合意义是:

\[[n]_q!=\sum_{p}q^{\text{inv}(p)} \]

也可以看成设 \(f_i\) 为长为 \(n\) 的排列中逆序对数为 \(i\) 的个数,\(f\) 的生成函数。证明就是考虑排列中 \(n\) 的位置。
定义 \(q\)-组合数为 \(\binom{n}{m}_q=\frac{[n]_q!}{[m]_q![n-m]_q!}\)
组合意义为设 \(f_i\)\(m\)\(0\)\(n-m\)\(1\) 的序列的全排列中逆序对数为 \(i\) 的个数,\(f\) 的生成函数。证明就是乘上 \(0\)\(1\) 内部的逆序对数后就是普通的排列。
还有一个组合意义就是所有 \((0,0)\)\((n,m)\) 的路径中,\(q\) 的下方格点数次幂的和。证明就是转成上面那个逆序对数。

slope trick

现在有一个 dp 数组 \(f_{i,x}\),且它是凸的。写成 \(f_i(x)\) 的形式,假设它长这样:
image
满足有若干个一次函数构成,且斜率都是整数,就能用四楼普垂克做一些东西。
设这些一次函数从左到右为 \(k_1x+b_1,\ldots,k_mx+b_m\),维护 \(k_1,b_1\) 和一个数据结构。
对于第 \(i\) 条直线和第 \(i-1\) 条直线的交点 \((x_i,y_i)\),在这个数据结构里插入 \(k_i-k_{i-1}\)\(x_i\),就能通过这些东西还原 \(f_{i,x}\)
对于两个凸性相同的凸函数 \(f(x)\)\(g(x)\),考虑怎么去快速维护 \(f(x)+g(x)\)。这个是简单的,显然它们加起来还是凸函数,把 \(k_1,b_1\) 加起来后合并那个数据结构就行。
若要查询极值,直接求出数据结构中第 \(|k|\) 小/大的数,然后查询那个位置的值。
若要做类似 \(f(x)\gets \min_{y\le x}f(y)\) 状物,只保留前 \(|k|\) 小/大就行。

闵可夫斯基和

对于两个上凸包 \((a_1,\ldots,a_n),(b_1,\ldots,b_m)\),考虑怎么求出它们的闵和。那两个序列表示点从左到右的序列。
显然第一个点是 \(a_1+b_1\),有个结论是,闵和上的边是原来的 \(n+m-1\) 条边按极角排序后的结果。
注意到两个凸包上的边已经排好序了,直接归并就行。

\(O(n)-O(1)\) RMQ

\(B=\log_2 n\),以 \(B\) 为块长分块,对每个块的极值建 ST 表,在预处理块内的前缀和后缀最大值,这些东西时间复杂度为 \(O(n)\)
你发现跨块询问是好做的,但是块内询问就爆了,那咋办。
把一个块单独拉出来。考虑 \([1,i]\) 构成的单调栈 \(p_{1},p_{2},\ldots,p_k\),你发现 \(p_1\) 一定是 \([1,i]\) 极值的位置,\(p_j\) 一定是 \((p_{j-1}+1,i]\) 极值的位置。
也就是说,\([l,r]\) 极值的位置一定是 \([1,r]\) 的单调栈 \(\ge l\) 的数中最小的那个。
考虑如何存下这个单调栈,你发现直接压位就行,找极值位置就是 l+__builtin_ctz(stack>>l)

斜率优化

有若干条一次函数 \(f_i(x)=k_ix+b_i\),需要支持动态加入和给定一个 \(x\) 查询 \(\max_{i}f_i(x)\)
\(kx+b\) 变成 \(b-(-x)k\) 的形式,可以发现这是用一条斜率为 \(-x\) 的直线穿过点 \((k,b)\) 的截距。
现在变成有若干个点,支持动态加点和查询用一条直线去穿过这些点的最大截距。
显然有用的点只会是这些点构成的上凸包上的点,维护这个凸包然后对斜率二分就行。

posted @ 2026-06-08 18:20  天域_awa  阅读(52)  评论(0)    收藏  举报