zoukankan      html  css  js  c++  java
  • LG4717 【模板】快速沃尔什变换

    快速沃尔什变换

    题目描述

    给定长度为(2^n)两个序列(A,B),设(C_i=sum_{joplus k}A_jB_k)分别当(oplus)是or,and,xor时求出C

    输入输出格式

    输入格式:

    第一行一个数n。 第二行(2^n)个数(A_0..A_{2^n-1})第三行(2^n)个数(B_0..B_{2^n-1})

    输出格式:

    三行每行(2^n)个数,分别代表(oplus)是or,and,xor时(C_0..C_{2^n-1})的值(mod 998244353)

    输入输出样例

    输入样例#1:

    2
    2 4 6 8
    1 3 5 7

    输出样例#1:

    2 22 46 250
    88 64 112 56
    100 92 68 60

    说明

    (nle 17)

    题解

    2015吕凯风论文和2013王迪论文。

    快速莫比乌斯变换

    这个只能用来做集合并和与卷积,但是容易理解。

    1
    2

    我通过《浅谈容斥原理》找到了另一种形式:

    那么通过相同的手段,就可以做集合交卷积。

    快速沃尔什变换

    这个理论有点复杂,现场推是不可能的,所以背版子吧。
    fwt

    还有类似FFT的实现,不过我反而觉得难写许多。

    代码总结

    • and是超集和变换(高维后缀和)。逆变换是超集差变换。

    • or是子集和变换(高维前缀和)。逆变换是子集差变换。

    • xor是蝴蝶变换。逆变换是最后除以长度。

    void FAT(poly&a,int dir){ // and -> superset
    	int lim=a.size(),len=log2(lim);
    	for(int j=0;j<len;++j)
    		for(int i=0;i<lim;++i)if(~i>>j&1)
    			a[i]=add(a[i],dir==1?a[i|1<<j]:mod-a[i|1<<j]);
    }
    void FOT(poly&a,int dir){ // or -> subset
    	int lim=a.size(),len=log2(lim);
    	for(int j=0;j<len;++j)
    		for(int i=0;i<lim;++i)if(i>>j&1)
    			a[i]=add(a[i],dir==1?a[i^1<<j]:mod-a[i^1<<j]);
    }
    void FXT(poly&a,int dir){ // xor
    	int lim=a.size(),len=log2(lim);
    	for(int j=0;j<len;++j)
    		for(int i=0;i<lim;++i)if(~i>>j&1){
    			int l=a[i],r=a[i|1<<j];
    			a[i]=add(l,r),a[i|1<<j]=add(l,mod-r);
    		}
    	if(dir==-1){
    		int ilim=fpow(lim,mod-2);
    		for(int i=0;i<lim;++i) a[i]=mul(a[i],ilim);
    	}
    }
    
    int main(){
    	int len=read<int>(),lim=1<<len;
    	poly f(lim),g(lim);
    	for(int i=0;i<lim;++i) read(f[i]);
    	for(int i=0;i<lim;++i) read(g[i]);
    	// or
    	poly a=f,b=g;
    	FOT(a,1),FOT(b,1);
    	for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
    	FOT(a,-1);
    	for(int i=0;i<lim;++i) printf("%d%c",a[i]," 
    "[i==lim-1]);
    	// and
    	a=f,b=g;
    	FAT(a,1),FAT(b,1);
    	for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
    	FAT(a,-1);
    	for(int i=0;i<lim;++i) printf("%d%c",a[i]," 
    "[i==lim-1]);
    	// xor
    	a=f,b=g;
    	FXT(a,1),FXT(b,1);
    	for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
    	FXT(a,-1);
    	for(int i=0;i<lim;++i) printf("%d%c",a[i]," 
    "[i==lim-1]);
    	return 0;
    }
    
  • 相关阅读:
    将一个数组分割为固定大小为三的的数组的数组
    计算两个日期间的天数
    手机号码影藏中间四位
    (反射)获取类的Class文件的三种方式
    Java程序员必背单词
    文本处理(CSS,JS)
    java学习路线
    onLoad onShow
    过滤HTML标签
    uni-app手机横屏后界面错乱解决办法
  • 原文地址:https://www.cnblogs.com/autoint/p/walsh_transformation.html
Copyright © 2011-2022 走看看