二进制位运算
常见的二进制位运算有:或,与,异或。分别对应了FMT,FMT与FWT。
下面从易到难介绍这几种运算。一下默认幂级数长度为2n2^n2n。
FMT
即快速莫比乌斯变化,定义也挺简单的。f(S)=∑T⊂Sg(T)f(S) = \sum_{T\subset S} g(T)f(S)=T⊂S∑g(T)
实际上就是子集和,同理定义快速莫比乌斯反演,即将快速莫比乌斯变化反演即可f^(S)=∑T⊂S(−1)∣S∣−∣T∣g(T)\hat{f}(S) = \sum_{T\subset S} (-1)^{|S| - |T|}g(T)f^(S)=T⊂S∑(−1)∣S∣−∣T∣g(T)
然后或卷积就明显可以通过此来优化。
同理就是与卷积。
定义是超集,反之亦然。
FWT
特别解决异或运算的。之后与kkk进制FWTFWTFWT一起写。
FST
就是failed system test
子集卷积。如果单纯做一个或卷积,那么势必答案是不对的,因为要求的条件实际上是
i | j == k && i & j == 0
而或卷积仅仅满足了第一个条件。那么多记一维表示应当有多少个即可。
k进制FWT
k进制下的异或任然是不进位加法,假设符号任然是⊕\oplus⊕,并且是数组A * B = C。
从原理上讲,正变换是我们要做的事情是找到这样一个矩阵www,使得原数组左乘上这个矩阵后还满足A * B = C。
逆变换是左乘这个矩阵的逆矩阵。那么考虑是什么意思
∑i⊕j=kAi∗Bj∗w(x,i)∗w(x,j)=Ck∗w(x,k)\sum \limits_{i \oplus j = k} A_i * B_j * w(x, i) * w(x, j) = C_k * w(x, k)i⊕j=k∑Ai∗Bj∗w(x,i)∗w(x,j)=Ck∗w(x,k)
对比系数可知
w(x,i)∗w(x,j)=w(x,k)  (i⊕j=k)w(x, i) * w(x, j) = w(x, k) \;(i \oplus j = k)w(x,i)∗w(x,j)=w(x,k)(i⊕j=k)
那么我们的目的即使找到这样的一个矩阵。
那么这样的性质让我们想到单位根:wki∗wkj=wki⊕jw_{k}^{i} * w_{k}^{j}=w_{k}^{i\oplus j}wki∗wkj=wki⊕j。从而联想到范德蒙德矩阵
[111...11wk1wk2...wkk−11wk2wk4...wk2(k−1)...............1wkk−1wk2(k−1)...wk(k−1)(k−1)]\begin{bmatrix}
1& 1 & 1& ... & 1\\
1& w_k^1& w_k^2& ... & w_k^{k - 1}\\
1& w_k^2 & w_k^4& ... & w_k^{2(k - 1)}\\
...& ...& ...& ...& ...\\
1& w_k^{k - 1}& w_k^{2(k - 1)} & ... & w_k^{(k - 1)(k - 1)}
\end{bmatrix}⎣⎢⎢⎢⎢⎡111...11wk1wk2...wkk−11wk2wk4...wk2(k−1)...............1wkk−1wk2(k−1)...wk(k−1)(k−1)⎦⎥⎥⎥⎥⎤
然后我们也知道其逆矩阵
1k[111...11wk−1wk−2...wk−(k−1)1wk−2wk−4...wk−2(k−1)...............1wk−(k−1)wk−2(k−1)...wk−(k−1)(k−1)]\frac{1}{k} \begin{bmatrix}
1& 1 & 1& ... & 1\\
1& w_k^{-1}& w_k^{-2}& ... & w_k^{-(k - 1)}\\
1& w_k^{-2} & w_k^{-4}& ... & w_k^{-2(k - 1)}\\
...& ...& ...& ...& ...\\
1& w_k^{-(k - 1)}& w_k^{-2(k - 1)} & ... & w_k^{-(k - 1)(k - 1)}
\end{bmatrix}k1⎣⎢⎢⎢⎢⎢⎡111...11wk−1wk−2...wk−(k−1)1wk−2wk−4...wk−2(k−1)...............1wk−(k−1)wk−2(k−1)...wk−(k−1)(k−1)⎦⎥⎥⎥⎥⎥⎤
然后不就完了?剩下的与正常的FWT一样的。就是答案由len / k的答案组合而来。同时要注意,如果是mod一个NTT质数的时候,有wn0=gmod−1nw_n^0 = g^{\frac{mod - 1}{n}}wn0=gnmod−1。
下面贴一份代码:
int wn[k];
inline int w(int x, int y) { return wn[(x * y) % k]; }
void FWT(int *a, int len, int coef) {
static int b[k];
int v;
for (int i = 1; i < len; i *= k) {
for (int j = 0; j < len; j += i * k) {
for (int k = j; k < j + i; k++) {
for (int d = 0; d < k; d++) {
b[d] = a[k + d * i];
a[k + d * i] = 0;
}
for (int d = 0; d < k; d++) {
v = k + d * i;
for (int _d = 0; _d < 4; _d++) {
a[v] = add(a[v], 1ll * w(d, coef * _d) * b[_d] % mod);
}
}
}
}
}
if (coef == -1) {
int Inv = qpow(len, mod - 2);
for (int i = 0; i < len; i++) a[i] = 1ll * Inv * a[i] % mod;
}
}
其中wn[i]=(gmod−1k)iwn[i] = (g^{\frac{mod - 1}{k}})^{i}wn[i]=(gkmod−1)i,coefcoefcoef为111时为正变换,−1-1−1时为逆变换。