多项式 - 快速沃尔什变换

若\(·\)是一种适用于整数域的二元运算,则两多项式关于此运算的方式定义为 \(C_k = \sum_{i·j=k} A_i * B_j\),即 \(C=A·B\)。

\(FWT\) 主要解决多项式的常见的三种二元位运算,在三种运算下分别构造出不同的变换方式,个人认为比 \(NTT\) 简单 好背 一些。形式与 \(NTT\) 近似。

 

没有新东西可说,直接放上洛谷模板题的代码好了:

#include <cmath>
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int mod = 998244353;
const int maxn = (1 << 17) + 10;
int n, m, limit, f_1[maxn], f_2[maxn], f_3[maxn], f_4[maxn], r[maxn];

class Walsh_transform_and {
public:
  inline void Fast_walsh_transform(int *a) {
    for(int mid = 1; mid < limit; mid = mid << 1)
      for(int l = 0, length = mid << 1; l < limit; l = l + length)
        for(int k = 0; k < mid; ++k) a[l + k] = (a[l + k] + a[l + mid + k]) % mod;
  }

  inline void Fast_walsh_inverform(int *a) {
    for(int mid = 1; mid < limit; mid = mid << 1)
      for(int l = 0, length = mid << 1; l < limit; l = l + length)
        for(int k = 0; k < mid; ++k) a[l + k] = (a[l + k] - a[l + mid + k] + mod) % mod;
  }
} calculate_and;

class Walsh_transform_or {
public:
  inline void Fast_walsh_transform(int *a) {
    for(int mid = 1; mid < limit; mid = mid << 1)
      for(int l = 0, length = mid << 1; l < limit; l = l + length)
        for(int k = 0; k < mid; ++k) a[l + mid + k] = (a[l + mid + k] + a[l + k]) % mod;
  }

  inline void Fast_walsh_inverform(int *a) {
    for(int mid = 1; mid < limit; mid = mid << 1)
      for(int l = 0, length = mid << 1; l < limit; l = l + length)
        for(int k = 0; k < mid; ++k) a[l + mid + k] = (a[l + mid + k] - a[l + k] + mod) % mod;
  }
} calculate_or;

class Walsh_transform_xor {
public:
  inline void Fast_walsh_transform(int *a) {
    for(int mid = 1; mid < limit; mid = mid << 1) {
      for(int l = 0, length = mid << 1; l < limit; l = l + length) {
        for(int k = 0; k < mid; ++k) {
          int x = a[l + k], y = a[l + mid + k];
          a[l + k] = (x + y) % mod, a[l + mid + k] = (x - y + mod) % mod;
        }
      }
    }
  }

  inline void Fast_walsh_inverform(int *a) {
    for(int mid = 1; mid < limit; mid = mid << 1) {
      for(int l = 0, length = mid << 1; l < limit; l = l + length) {
        for(int k = 0; k < mid; ++k) {
          int x = a[l + k], y = a[l + mid + k];
          a[l + k] = (x + y) % mod, a[l + mid + k] = (x - y + mod) % mod;
          a[l + k] = (a[l + k] & 1) ? (a[l + k] + mod) >> 1 : a[l + k] >> 1;
          a[l + mid + k] = (a[l + mid + k] & 1) ? (a[l + mid + k] + mod) >> 1 : a[l + mid + k] >> 1;
        }
      }
    }
  }
} calculate_xor;

inline int read() {
  register char ch = 0; register int w = 0, x = 0;
  while( !isdigit(ch) ) w |= (ch == ‘-‘), ch = getchar();
  while( isdigit(ch) ) x = (x * 10) + (ch ^ 48), ch = getchar();
  return w ? -x : x;
}

int main(int argc, char const *argv[])
{
  freopen("..\\nanjolno.in", "r", stdin);
  freopen("..\\nanjolno.out", "w", stdout);

  n = read(), limit = (1 << n);
  for(int i = 0; i < limit; ++i) f_1[i] = read();
  for(int i = 0; i < limit; ++i) f_2[i] = read();

  for(int i = 0; i < limit; ++i) f_3[i] = f_1[i];
  for(int i = 0; i < limit; ++i) f_4[i] = f_2[i];
  calculate_or.Fast_walsh_transform(f_3);
  calculate_or.Fast_walsh_transform(f_4);
  for(int i = 0; i < limit; ++i) r[i] = (1ll * f_3[i] * f_4[i]) % mod;
  calculate_or.Fast_walsh_inverform(r);
  for(int i = 0; i < limit; ++i) printf("%d ", r[i]);
  printf("\n");

  for(int i = 0; i < limit; ++i) f_3[i] = f_1[i];
  for(int i = 0; i < limit; ++i) f_4[i] = f_2[i];
  calculate_and.Fast_walsh_transform(f_3);
  calculate_and.Fast_walsh_transform(f_4);
  for(int i = 0; i < limit; ++i) r[i] = (1ll * f_3[i] * f_4[i]) % mod;
  calculate_and.Fast_walsh_inverform(r);
  for(int i = 0; i < limit; ++i) printf("%d ", r[i]);
  printf("\n");

  for(int i = 0; i < limit; ++i) f_3[i] = f_1[i];
  for(int i = 0; i < limit; ++i) f_4[i] = f_2[i];
  calculate_xor.Fast_walsh_transform(f_3);
  calculate_xor.Fast_walsh_transform(f_4);
  for(int i = 0; i < limit; ++i) r[i] = (1ll * f_3[i] * f_4[i]) % mod;
  calculate_xor.Fast_walsh_inverform(r);
  for(int i = 0; i < limit; ++i) printf("%d ", r[i]);
  printf("\n");

  fclose(stdin), fclose(stdout);
  return 0;
}

 

                  天也醉樱花,云脚乱蹒跚。

原文地址:https://www.cnblogs.com/nanjoqin/p/10358107.html

时间: 2024-11-02 01:22:17

多项式 - 快速沃尔什变换的相关文章

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_

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)的和 当然,异或也可以换成&,|这些运算符

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

luoguP5245 【模板】多项式快速幂

$B(x)=A^k(x)$ $\Rightarrow \ln B(x)=\ln A^k(x)$ $\Rightarrow \ln B(x)=k \ln A(x)$ $\Rightarrow B(x)=\exp(k \ln A(x))$ code: #include <cmath> #include <cstring> #include <algorithm> #include <cstdio> #include <string> #define

luoguP5219 无聊的水题 I 多项式快速幂

有一个幼儿园容斥:最大次数恰好为 $m=$  最大次数最多为 $m$ - 最大次数最多为 $m-1$. 然后来一个多项式快速幂就好了. code: #include <cmath> #include <cstring> #include <algorithm> #include <cstdio> #include <string> #define ll long long #define ull unsigned long long using

【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂

[BZOJ3992][SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S. 小C用这个生成器生成了许多这样的数列.但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个.小C认为,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi.另外,小C认为这个问题的答案可能

关于快速沃尔什变换(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的思路,采用分治的想法. 首先先把多项式的长度用