FWT

一、处理的问题:

给出两个序列\(A,B\),求出序列\(C\),其中\(C_i=\sum\limits_{j\oplus k=i}A_j*B_k\),其中\(\oplus\)是一种运算。

二、举例

我们运用\(FFT\)的思想,考虑先对\(A,B\)构造一个序列\(FWT(A)\)\(FWT(B)\),满足\(FWT(C)_i=FWT(A)_i*FWT(B)_i\),之后再从\(FWT(C)\)转为\(C\)

拿或运算举例:

如果有\(k=i\mid j\),那么\(i,j\)必定是\(k\)的子集。

我们首先构造\(FWT(A)_i=A'_i=\sum\limits_{i=i|j}A_j\),表示\(j\)\(i\)的子集。

那么就会有:
\(C'_i=\sum\limits_{i=i|(j|k)}C_{j|k}=\sum\limits_{i=i|j}A_j*\sum\limits_{i=i|k}B_k=A'_i*B'_i\)
即:
\(FWT(C)_i=FWT(A)_i*FWT(B)_i\)

现在考虑怎么求\(FWT(A)\)

暴力显然是\(O(n^2)\)的(对每个\(i\)枚举\(j\)),我们考虑分治。

这时我们将\(A\)一分为二,我们令\(A_1\)表示序列\(A\)的前半段,\(A_2\)表示\(A\)的后半段。

这时我们发现:
\(FWT(A)=merge(FWT(A_1),FWT(A_1)+FWT(A_2))\)
其中\(merge\)表示将两个序列前后拼接在一起,\(+\)表示每一位相加。

因为对于\(FWT(A)\)的前半段,因为当前二进制最高位为\(0\),所以它就等于\(FWT(A_1)\)

而对于\(FWT(A)\)的后半段,首先它肯定有\(FWT(A_2)\),我们考虑\(A_1\)中的元素对\(FWT(A)\)后半段的贡献。

我们设\(len(A_1)=len(A_2)=l\)

那么对于\(i,\(i\)\(i+l\)只在最高位上差了\(1\),而我们已经最高位为\(1\)的都统计进了\(FWT(A_2)\),这时\(FWT(A)_i\)存的就是\(FWT(A)_{i+l}\)缺少的所有\(A_j\)

于是我们可以递归分治\(O(nlogn)\)来进行\(FWT\)

我们求出\(FWT(C)\)之后还要进行逆变换,于是我们考虑\(IFWT\)怎么做。

其实\(IFWT\)很简单,我们只要按照刚才\(FWT\)时的过程逆着来一遍即可。

\(IFWT(C)=merge(IFWT(C_1),IFWT(C_2)-IFWT(C_1))\)

三、推广

更广泛地说,我们定义\(\oplus\)\(FWT\)为:
\(A'=\{\sum\limits_{i\oplus j=0}A_i*B_j,\sum\limits_{i\oplus j=1}A_i*B_j,...,\sum\limits_{i\oplus j=n-1}A_i*B_j\}\)

现在给出其它运算的\(FWT\)求法:

与或运算相同,我们可以推出与运算的求法:
\(FWT(A)=merge(FWT(A_1)+FWT(A_2),FWT(A_2))\)
\(IFWT(A)=merge(IFWT(A_1)-IFWT(A_2),IFWT(A_2))\)

异或运算:
直接抄结论(不会证):
\(FWT(A)=(FWT(A_1)+FWT(A_2),FWT(A_1)-FWT(A_2))\)
\(IFWT(A)=(\frac{FWT(A_1)+FWT(A_2)}{2},\frac{FWT(A_1)-FWT(A_2)}{2})\)

同或(我今天才知道有这么个东西):
\(FWT(A)=(FWT(A_2)-FWT(A_1),FWT(A_2)+FWT(A_1))\)
\(IFWT(A)=(\frac{FWT(A_2)-FWT(A_1)}{2},\frac{FWT(A_2)+FWT(A_1)}{2})\)

模板题

code:

#include
using namespace std;
typedef long long ll;
const int maxn=(1<<17)+10;
const ll mod=998244353;
const ll inv2=mod+1>>1;
int n,m;
ll A[maxn],B[maxn],a[maxn],b[maxn],c[maxn];
inline ll read()
{
    char c=getchar();ll res=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    return res*f;
}
void fwt_or(ll* a,int op)
{
    for(int mid=1;mid

你可能感兴趣的:(FWT)