zoukankan      html  css  js  c++  java
  • FWT背板笔记

    板子

    背板子.jpg

    (Fwt)用于解决这样的问题

    [C_i=sum_{jigoplus k=i}A_j imes B_k ]

    其中(igoplus)是一种二元运算符,如(or,and,xor)

    首先我们直接做复杂度显然高达(4^n),或许可以利用一些枚举子集的技术做到(3^n),但是还是非常难以接受

    于是我们考虑能否像(fft)那样构造出一种变换(tf),使得(tf(C)=tf(A)*tf(B))(这里是逐位相乘),同时快速完成这个变换以及逆变换呢

    下面以(or)卷积为例

    我们设(tf(A)(i)=sum_{j|i=i}A_j)

    发现这个(j|i=i)就是说(j)(i)的子集啊

    于是

    [tf(A)(i)*tf(B)(i)=sum_{j|i=i}A_j imes sum_{k|i=i}B_k ]

    既然(j,k)都是(i)的子集,那么(j|k)显然也是(i)的子集,设(t=j|k)

    于是

    [tf(A)(i)*tf(B)(i)=sum_{(k|j)|i=i}A_j imes B_k=sum_{t|i=i}C_t=tf(C)(i) ]

    我们发现如果这样构造(tf),我们是可以得到(tf(A)*tf(B)=tf(C))这样的性质的,于是就可以像(fft)那样直接逐位相乘之后逆变换了

    考虑如何进行变换

    变换如下

    [tf(A)=egin{cases}(tf(A_0),tf(A_0+A_1)) & ngt0 \ A & n=0end{cases} ]

    (A_0)(A)的前(2^{n-1})项组成的多项式,(A_1)是后(2^{n-1})项组成的多项式

    (n=0)的时候,(tf(A)=A)成立这非常显然啊

    考虑一下(n>0)的情况

    那个((tf(A_0),tf(A_0+A_1)))就是把两个(2^{n-1})的多项式连接起来的意思

    我们对于(tf(A))的前(2^{n-1})项,就是(A_0)的变换,跟(A_1)没有什么关系,因为这前(2^{n-1})项第(n)位都是(0),不可能跟后(2^{n-1})项第(n)位都是(1)产生关系

    考虑后(2^{n-1})项,根据一个非常感性的理解,后(2^{n-1})项的第(n)位都是(1),我们构造出多项式(A_0+A_1),只看后面的(n-1)位自然是满足我们的(tf)的规则的,就是(j)(i)的子集,又由于(i)的第一位是(1),所以(j)的第一位是(0)(1)都可以,所以我们直接用(A_0+A_1)就好了

    类似的,我们也可以推出逆变换

    [itf(A)=egin{cases}(itf(A_0),itf(A_0-A_1)) & ngt0 \ A & n=0end{cases} ]

    于是我们就可以写出(or)卷积的代码

    inline void Fwtor(LL *f,int o) {
    	for(re int i=2;i<=len;i<<=1)
    		for(re int ln=i>>1,l=0;l<len;l+=i)
    			for(re int x=l;x<l+ln;++x)
    				f[ln+x]+=o*f[x];
    }
    

    (and)卷积和(or)卷积类似

    我们设变换(tf(A)(i)=sum_{j&i=i}A_j)

    发现(j&i=i)就是说(j)(i)的超集

    我们也能相应写出变换

    [tf(A)=egin{cases}(tf(A_0+A_1),tf(A_1)) & ngt0 \ A & n=0end{cases} ]

    以及逆变换

    [itf(A)=egin{cases}(itf(A_0-A_1),itf(A_1)) & ngt0 \ A & n=0end{cases} ]

    以及代码

    inline void Fwtand(LL *f,int o) {
    	for(re int i=2;i<=len;i<<=1)
    		for(re int ln=i>>1,l=0;l<len;l+=i)
    			for(re int x=l;x<l+ln;++x)
    				f[x]+=o*f[ln+x];
    }
    

    (xor)卷积就有些不一样了呀

    首先我不是很知道这个变换的实际含义是什么

    据fuge说是曼哈顿距离转切比雪夫距离

    我们直接摆结论

    [tf(A)=egin{cases}(tf(A_0+A_1),tf(A_0-A_1)) & ngt0 \ A & n=0end{cases} ]

    尝试证明一下?对不起我咕了,挂一个yyb跑路了

    板子还是放上来吧

    inline void Fwtxor(LL *f,int o) {
    	LL Inv;
    	if(o==1) Inv=1;else Inv=ksm(2,mod-2);
    	for(re int i=2;i<=len;i<<=1)
    		for(re int ln=i>>1,l=0;l<len;l+=i)
    			for(re int x=l;x<l+ln;++x) {
    				LL g=f[x],h=f[ln+x];
    				f[x]=(g+h)%mod,f[ln+x]=(g-h+mod)%mod;
    				f[x]=(f[x]*Inv)%mod;f[ln+x]=(f[ln+x]*Inv)%mod;
    			}
    }
    

    最后挂一个完整的板子吧

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define re register
    #define LL long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    const int maxn=(1<<17)+6;
    inline int read() {
    	char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    const int mod=998244353;
    int n,len;
    LL A[maxn],B[maxn],a[maxn],b[maxn];
    inline void Fwtor(LL *f,int o) {
    	for(re int i=2;i<=len;i<<=1) 
    		for(re int ln=i>>1,l=0;l<len;l+=i)	
    			for(re int x=l;x<l+ln;++x)
    				f[x+ln]+=f[x]*o,f[x+ln]=(f[x+ln]+mod)%mod;
    }
    inline void Fwtand(LL *f,int o) {
    	for(re int i=2;i<=len;i<<=1) 
    		for(re int ln=i>>1,l=0;l<len;l+=i)
    			for(re int x=l;x<l+ln;++x)
    				f[x]+=f[x+ln]*o,f[x]=(f[x]+mod)%mod;
    }
    inline void Fwtxor(LL *f,int o) {
    	int Inv;
    	if(o==1) Inv=1;else Inv=499122177;
    	for(re int i=2;i<=len;i<<=1) 
    		for(re int ln=i>>1,l=0;l<len;l+=i) 
    			for(re int x=l;x<l+ln;++x) {
    				int g=f[x],h=f[x+ln];
    				f[x]=(g+h)%mod;f[ln+x]=(g-h+mod)%mod;
    				f[x]=1ll*f[x]*Inv%mod;f[x+ln]=1ll*f[x+ln]*Inv%mod;
    			}
    }
    int main() {
    	n=read();len=(1<<n);
    	for(re int i=0;i<len;i++) a[i]=A[i]=read();
    	for(re int i=0;i<len;i++) b[i]=B[i]=read();
    	Fwtor(A,1),Fwtor(B,1);
    	for(re int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod;
    	Fwtor(A,-1);
    	for(re int i=0;i<len;i++) printf("%lld ",A[i]);puts("");
    	for(re int i=0;i<len;i++) A[i]=a[i];
    	for(re int i=0;i<len;i++) B[i]=b[i];
    	Fwtand(A,1),Fwtand(B,1);
    	for(re int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod;
    	Fwtand(A,-1);
    	for(re int i=0;i<len;i++) printf("%lld ",A[i]);puts("");
    	for(re int i=0;i<len;i++) A[i]=a[i];
    	for(re int i=0;i<len;i++) B[i]=b[i];
    	Fwtxor(A,1),Fwtxor(B,1);
    	for(re int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod;
    	Fwtxor(A,-1);
    	for(re int i=0;i<len;i++) printf("%lld ",A[i]);puts("");
    	return 0;
    }
    
  • 相关阅读:
    Atitit 集团与个人的完整入口列表 attilax的完整入口 1. 集团与个人的完整入口列表 1 2. 流量入口概念 2 3. 流量入口的历史与发展 2 1.集团与个人的完整入口列表
    atitit 每季度日程表 每季度流程 v3 qaf.docx Ver history V2 add diary cyar data 3 cate V3 fix detail 3cate ,
    Atitit react 详细使用总结 绑定列表显示 attilax总结 1. 前言 1 1.1. 资料数量在百度内的数量对比 1 1.2. 版本16 v15.6.1 1 1.3. 引入js 2
    Atitit r2017 r3 doc list on home ntpc.docx
    Atitit r2017 ra doc list on home ntpc.docx
    Atiitt attilax掌握的前后技术放在简历里面.docx
    Atitit q2016 qa doc list on home ntpc.docx
    Atitit r7 doc list on home ntpc.docx 驱动器 D 中的卷是 p2soft 卷的序列号是 9AD0D3C8 D:\ati\r2017 v3 r01\
    Atitit 可移植性之道attilax著
    Atitit q2016 q5 doc list on home ntpc.docx
  • 原文地址:https://www.cnblogs.com/asuldb/p/10686125.html
Copyright © 2011-2022 走看看