[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];
inline ll Add(ll x,ll y) {x+=y; return x>=P ? x-P : x;}
inline ll Div(ll x) {return x&1 ? (x+P)>>1 : x>>1;}
namespace XOR {
    inline void FWT(ll *a,int n,int type) {
        for(int haf=1;haf<n;haf<<=1)
            for(int st=0,d=haf<<1;st<n;st+=d)
                for(int i=0;i<haf;i++) {
                    int x=a[st+i],y=a[st+haf+i];
                    if(type) {
                        a[st+i]=Add(x,y);
                        a[st+haf+i]=Add(x,-y+P);
                    } else {
                        a[st+i]=Div(Add(x,y));
                        a[st+haf+i]=Div(Add(x,-y+P));
                    }
                }
    }
}
namespace OR {
    inline void FWT(ll *a,int n,int type) {
        for(int haf=1;haf<n;haf<<=1)
            for(int st=0,d=haf<<1;st<n;st+=d)
                for(int i=0;i<haf;i++) {
                    a[st+haf+i]+=a[st+i]*type+P;
                    if(a[st+haf+i]>=P) a[st+haf+i]-=P;
                    if(a[st+haf+i]>=P) a[st+haf+i]-=P;
                }
    }
}
namespace AND {
    inline void FWT(ll *a,int n,int type) {
        for(int haf=1;haf<n;haf<<=1)
            for(int st=0,d=haf<<1;st<n;st+=d)
                for(int i=0;i<haf;i++) {
                    a[st+i]+=a[st+haf+i]*type+P;
                    if(a[st+i]>=P) a[st+i]-=P;
                    if(a[st+i]>=P) a[st+i]-=P;
                }
    }
}

signed main() {
    read(n); n=1<<n;
    for(int i=0;i<n;i++) read(A[i]);
    for(int i=0;i<n;i++) read(B[i]);

    memcpy(a,A,sizeof(A)); memcpy(b,B,sizeof(B));
    OR::FWT(a,n,1),OR::FWT(b,n,1);
    for(int i=0;i<n;i++) c[i]=a[i]*b[i]%P;
    OR::FWT(c,n,-1); for(int i=0;i<n;i++) printf("%lld ",c[i]); puts("");

    memcpy(a,A,sizeof(A)); memcpy(b,B,sizeof(B));
    AND::FWT(a,n,1),AND::FWT(b,n,1);
    for(int i=0;i<n;i++) c[i]=a[i]*b[i]%P;
    AND::FWT(c,n,-1); for(int i=0;i<n;i++) printf("%lld ",c[i]); puts(""); 

    memcpy(a,A,sizeof(A)); memcpy(b,B,sizeof(B));
    XOR::FWT(a,n,1),XOR::FWT(b,n,1);
    for(int i=0;i<n;i++) c[i]=a[i]*b[i]%P;
    XOR::FWT(c,n,0); for(int i=0;i<n;i++) printf("%lld ",c[i]); puts("");

    return 0;
}

用时:5min

原文地址:https://www.cnblogs.com/functionendless/p/9556685.html

时间: 2024-11-11 02:27:56

[LUOGU 4717] 快速沃尔什变换的相关文章

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\)表示对于某一列而言,若它经过各种行操作

快速沃尔什变换

快速沃尔什变换 题目背景 模板题,无背景 题目描述 给定长度为\(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

关于快速沃尔什变换(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

多项式 - 快速沃尔什变换

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