快速沃尔什变换

快速沃尔什变换

题目背景

模板题,无背景

题目描述

给定长度为\(2^n\)两个序列\(A,B\),设\(C_i=\sum_{j\oplus k=i}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}\)的值\(\bmod\ 998244353\)

说明

\(n\le 17\)。



证明没怎么看懂,放结论了。

or

\[FWT(A)=(FWT(A_0),FWT(A_0+A_1))\]

\[IFWT(A)=(IFWT(A_0),IFWT(A_1-A_0))\]

and

\[FWT(A)=(FWT(A_0+A_1),FWT(A_1))\]

\[IFWT(A)=(IFWT(A_0-A_1),IFWT(A_1))\]

xor

\[FWT(A)=(FWT(A_0+A_1),FWT(A_0-A_1))\]

\[IFWT(A)=(IFWT(A_0+A_1)/2,IFWT(A_1-A_0)/2)\]

背下来吧,像\(FFT\)那样写就好了



Code:

#include <cstdio>
const int N=(1<<17)+10;
const int mod=998244353,inv=499122177;
int A[N],B[N],a[N],b[N],n,len;
#define add(a,b) ((a+b)%mod)
#define mul(a,b) (1ll*(a)*(b)%mod)
void orfwt(int *a,int typ)
{
    for(int le=1;le<len;le<<=1)
        for(int p=0;p<len;p+=le<<1)
            for(int i=p+le;i<p+(le<<1);i++)
                if(typ) a[i]=add(a[i],a[i-le]);
                else a[i]=add(a[i],mod-a[i-le]);
}
void andfwt(int *a,int typ)
{
    for(int le=1;le<len;le<<=1)
        for(int p=0;p<len;p+=le<<1)
            for(int i=p;i<p+le;i++)
                if(typ) a[i]=add(a[i],a[i+le]);
                else a[i]=add(a[i],mod-a[i+le]);
}
void xorfwt(int *a,int typ)
{
    for(int le=1;le<len;le<<=1)
        for(int p=0;p<len;p+=le<<1)
            for(int i=p;i<p+le;i++)
            {
                int tx=a[i],ty=a[i+le];
                a[i]=add(tx,ty),a[i+le]=add(tx,mod-ty);
                if(!typ) a[i]=mul(a[i],inv),a[i+le]=mul(a[i+le],inv);
            }
}
int main()
{
    scanf("%d",&n);len=1<<n;
    for(int i=0;i<len;i++) scanf("%d",A+i);
    for(int i=0;i<len;i++) scanf("%d",B+i);
    for(int i=0;i<len;i++) a[i]=A[i],b[i]=B[i];
    orfwt(a,1),orfwt(b,1);
    for(int i=0;i<len;i++) a[i]=mul(a[i],b[i]);
    orfwt(a,0);
    for(int i=0;i<len;i++) printf("%d ",a[i]);
    puts("");

    for(int i=0;i<len;i++) a[i]=A[i],b[i]=B[i];
    andfwt(a,1),andfwt(b,1);
    for(int i=0;i<len;i++) a[i]=mul(a[i],b[i]);
    andfwt(a,0);
    for(int i=0;i<len;i++) printf("%d ",a[i]);
    puts("");

    for(int i=0;i<len;i++) a[i]=A[i],b[i]=B[i];
    xorfwt(a,1),xorfwt(b,1);
    for(int i=0;i<len;i++) a[i]=mul(a[i],b[i]);
    xorfwt(a,0);
    for(int i=0;i<len;i++) printf("%d ",a[i]);
    puts("");
    return 0;
}


2018.12.18

原文地址:https://www.cnblogs.com/ppprseter/p/10136407.html

时间: 2024-10-07 05:07:26

快速沃尔什变换的相关文章

Fast Walsh-Hadamard Transform——快速沃尔什变换

模板题: 给定$n = 2^k$和两个序列$A_{0..n-1}$, $B_{0..n-1}$,求 $$C_i = \sum_{j \oplus k = i} A_j B_k$$ 其中$\oplus$是某一满足交换律的位运算,要求复杂度$O(nlogn)$. 快速沃尔什变换: 这是什么东西?有用吗?请参阅SDOI2017r2d1-cut. 看到这个大家是不是立刻想到了快速傅里叶变换? $$C_i = \sum_{j + k = i} A_j B_k$$ 我们来想想离散傅里叶变换的本质. $$\b

Codeforces 662C(快速沃尔什变换 FWT)

感觉快速沃尔什变换和快速傅里叶变换有很大的区别啊orz 不是很明白为什么位运算也可以叫做卷积(或许不应该叫卷积吧) 我是看 http://blog.csdn.net/liangzhaoyang1/article/details/52819835 里的快速沃尔什变换 这里说一下自己的理解吧,快速傅里叶变换是计算卷积的,就是∑f(x)*g(n-x)这种 快速沃尔什变换也是计算∑f(x)*g(y) ,但这里是计算所有的满足x^y = n(卷积是计算x+y=n)的和 当然,异或也可以换成&,|这些运算符

FWT快速沃尔什变换学习笔记

FWT快速沃尔什变换学习笔记 1.FWT用来干啥啊 回忆一下多项式的卷积\(C_k=\sum_{i+j=k}A_i*B_j\) 我们可以用\(FFT\)来做. 甚至在一些特殊情况下,我们\(C_k=\sum_{i*j=k}A_i*B_j\)也能做(SDOI2015 序列统计). 但是,如果我们把操作符换一下呢? 比如这样? \(C_k=\sum_{i|j=k}A_i*B_j\) \(C_k=\sum_{i\&j=k}A_i*B_j\) \(C_k=\sum_{i\wedge j=k}A_i*B_

Codeforces 662C Binary Table(快速沃尔什变换)

Problem 给定一个n(≤20)*m(≤100 000)的01矩阵,每次操作可以将一行或一列取反. 求最终1的最少个数. Solution 前置技能:快速沃尔什变换(FWT). 观察到n较小,考虑\(O(2^n)\)枚举每一行选或不选. 不妨设f(x)表示行的操作状态为x时(我们可用一个二进制数表示状态),经过各种列操作后所得到的最少的1的个数. 可以\(O(m)\)再扫一遍所有列.但显然T飞了. 定义\(C_j\)表示有多少列的状态为j:\(E_k\)表示对于某一列而言,若它经过各种行操作

关于快速沃尔什变换(FWT)的一些个人理解

定义 FWT是一种快速完成集合卷积运算的算法. 它可以用于求解类似C[i]=∑j?k=i A[j]*B[k]的问题. 其中?代表位运算中的|,&,^的其中一种. 求解(正变换) 设F(A)是对于A的一种变换. 并且F(A)要求满足:   F(A)*F(B)=F(A?B) ①  k*F(A)=F(k*A)   ② F(A+B)=F(A)+F(B) ③ (A,B长度相同) 鉴于FWT和FFT长得特别像(而且求解的问题也比较类似),我们可以借鉴一下FFT的思路,采用分治的想法. 首先先把多项式的长度用

快速沃尔什变换与k进制FWT

这是一篇用来卖萌的文章QAQ 考虑以下三类卷积 \(C_k = \sum \limits_{i \;or\;j = k} A_i * B_j\) \(C_k = \sum \limits_{i\;and\;j = k} A_i * B_j\) \(C_k = \sum \limits_{i\;xor\;j = k}A_i * B_j\) 由于前两种可以用FMT(高维前缀和)解决,那我们就谈谈第三种吧 下文中的\(n\)都是形如\(2^i - 1\)的数 下标的开与闭是根据好不好写来定的,但是还是

BZOJ4589 Hard Nim(快速沃尔什变换模板)

终于抽出时间来学了学,比FFT不知道好写到哪里去. #include <cstdio> typedef long long ll; const int N=65536,p=1e9+7; int k,m,n,a[N],pi[N]; bool pr(int x) {for(int i=2;i*i<=x;i++) if(x%i==0) return 0; return 1;} ll pw(ll a,int b) {ll r=1; for(;b;b>>=1,a=a*a%p) if(b

[LUOGU 4717] 快速沃尔什变换

题目传送-Luogu4717 题意: 给你\(A\),\(B\),求\[C_i=\sum_{j\oplus k=i}A_j*B_k \] \(\oplus\)包括\(or\),\(and\),\(xor\) \(len\le 2^{17}\) 题解: 裸的\(FWT\),总结先留坑 过程: 一切顺利 代码: const int BIT=17,N=1<<BIT; const ll P=998244353; int n; ll A[N],B[N]; ll a[N],b[N],c[N]; inlin

多项式 - 快速沃尔什变换

若\(·\)是一种适用于整数域的二元运算,则两多项式关于此运算的方式定义为 \(C_k = \sum_{i·j=k} A_i * B_j\),即 \(C=A·B\). \(FWT\) 主要解决多项式的常见的三种二元位运算,在三种运算下分别构造出不同的变换方式,个人认为比 \(NTT\) 简单 好背 一些.形式与 \(NTT\) 近似. 没有新东西可说,直接放上洛谷模板题的代码好了: #include <cmath> #include <queue> #include <cst