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;
    }
    
  • 相关阅读:
    Scrum框架及其背后的原则(上)——Scrum 框架的伪代码描述[转载自InfoQ]
    用程序给闺女出算数题——我的头脑体操
    敏捷实践调查结果[翻译转载]
    一.初识Selenium
    二.Selenium安装相关文件
    Review of American Beauty(unoriginal)
    三.Selenium IDE学习
    将Java Project转变为Dynamic Web Project
    功能自动化工具watiJ(转载)
    Selenium前奏
  • 原文地址:https://www.cnblogs.com/asuldb/p/10686125.html
Copyright © 2011-2022 走看看