k进制快速沃尔什变换(k进制FWT)

2023-10-10 05:20

本文主要是介绍k进制快速沃尔什变换(k进制FWT),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引入

我们已经知道了多项式版的二进制 FWT,但是我们似乎不是很好将其扩展到 k k k 进制下,于是我们来考虑另一种方式的 FWT。

原理

二进制

规定三个多项式的长度为 2 n 2^n 2n,如果不够则往后面补 0 0 0

还是先考虑二进制,我们假设存在矩阵使得 T A ∗ T B = T C TA * TB = TC TATB=TC,考虑矩阵长什么样。

我们可以得到如下式子

F W T ( A ) x = ∑ i = 0 2 n − 1 w x , i ∗ A i FWT(A)_{x}=\sum_{i = 0}^{2^n-1}w_{x,i}*A_i FWT(A)x=i=02n1wx,iAi

因为 F W T ( A ) ∗ F W T ( B ) = F W T ( C ) FWT(A)*FWT(B)=FWT(C) FWT(A)FWT(B)=FWT(C),所以 F W T ( A ) x ∗ F W T ( B ) x = F W T ( C ) x FWT(A)_x*FWT(B)_x=FWT(C)_x FWT(A)xFWT(B)x=FWT(C)x,可写为

∑ i = 0 2 n − 1 w x , i ∗ A i ∗ ∑ j = 0 2 n − 1 w x , j ∗ B j = ∑ k = 0 2 n − 1 w x , k ∗ C k \sum_{i = 0}^{2^n-1}w_{x,i}*A_i * \sum_{j= 0}^{2^n-1}w_{x,j}*B_j=\sum_{k= 0}^{2^n-1}w_{x,k}*C_k i=02n1wx,iAij=02n1wx,jBj=k=02n1wx,kCk

∑ i = 0 2 n − 1 ∑ j = 0 2 n − 1 w x , i ∗ w x , j ∗ A i ∗ B j = ∑ k = 0 2 n − 1 w x , k ∗ C k \sum_{i=0}^{2^n-1}\sum_{j= 0}^{2^n-1}w_{x,i}* w_{x,j}*A_i *B_j=\sum_{k= 0}^{2^n-1}w_{x,k}*C_k i=02n1j=02n1wx,iwx,jAiBj=k=02n1wx,kCk

因为我们要使得

∑ i ⊕ j = k A i ∗ B j = C k \sum_{i\oplus j=k} A_i*B_j=C_k ij=kAiBj=Ck

即要使得以下式子成立

∑ i ⊕ j = k w x , i ∗ w x , j ∗ A i ∗ B j = w x , k ∗ C k \sum_{i\oplus j = k}w_{x,i}* w_{x,j}*A_i *B_j=w_{x,k}*C_k ij=kwx,iwx,jAiBj=wx,kCk

所以我们可以得出

w x , i ∗ w x , j = w x , k ( i ⊕ j = k ) w_{x,i}*w_{x,j} = w_{x,k}\ \ \ \ (i\oplus j = k) wx,iwx,j=wx,k    (ij=k)

此时的矩阵就是范德蒙德矩阵。(就是我们再莫比乌斯反演里面学的哪个单位根矩阵)

我们考虑如何快速求出 F W T ( A ) x FWT(A)_x FWT(A)x

我们定义 A 0 A_0 A0 表示前半段, A 1 A_1 A1 表示后半段, x 1 x_1 x1 表示 x x x 的最高位(如果最高位为 1 1 1 x 1 x_1 x1 1 1 1,否则为 0 0 0), x 0 x_0 x0 表示 x x x 除了最高位其他的位, i 0 i_0 i0 也表示 i i i 除了最高位其它的位。

则我们可以推出

F W T ( A ) x = ∑ i = 0 2 n − 1 w x , i ∗ A i = ∑ i = 0 2 n − 1 − 1 w x , i ∗ A i + ∑ i = 2 n 2 n − 1 w x , i ∗ A i = ∑ i = 0 2 n − 1 − 1 w x 1 , 0 ∗ w x 0 , i 0 ∗ A i + ∑ i = 2 n 2 n − 1 w x 1 , 1 ∗ w x 0 , i 0 ∗ A i = w x 1 , 0 ∗ F W T ( A 0 ) x 0 + w x 1 , 1 ∗ F W T ( A 1 ) x 0 \begin{aligned} FWT(A)_{x}&=\sum_{i = 0}^{2^n-1}w_{x,i}*A_i\\ &=\sum_{i = 0}^{2^{n - 1} - 1}w_{x,i}*A_i+\sum_{i = 2^n}^{2^n - 1}w_{x,i}*A_i\\ &=\sum_{i = 0}^{2^{n - 1} - 1}w_{x_1,0}*w_{x_0,i_0}*A_i+\sum_{i = 2^n}^{2^n - 1}w_{x_1,1}*w_{x_0,i_0}*A_i\\ &=w_{x_1,0}*FWT(A_0)_{x_0}+w_{x_1,1}*FWT(A_1)_{x_0} \end{aligned} FWT(A)x=i=02n1wx,iAi=i=02n11wx,iAi+i=2n2n1wx,iAi=i=02n11wx1,0wx0,i0Ai+i=2n2n1wx1,1wx0,i0Ai=wx1,0FWT(A0)x0+wx1,1FWT(A1)x0

于是就跟多项式下的 FWT 一样可以递归求了。

k进制

于是我们进入正题,来看看 k k k 进制下的 FWT。(其实跟二进制下很像,只不过有一些细节上的区别)

同样规定多项式长度为 k n k^n kn

还是要构造矩阵使得 T A ∗ T B = T C TA * TB = TC TATB=TC

同样有

F W T ( A ) x = ∑ i = 0 k n − 1 w x , i ∗ A i = ∑ i = 0 k − 1 w x 1 , i ∗ F W T ( A i ) x 0 \begin{aligned} FWT(A)_{x}&=\sum_{i = 0}^{k^n-1}w_{x,i}*A_i\\ &=\sum_{i = 0}^{k - 1}w_{x_1,i}*FWT(A_i)_{x_0} \end{aligned} FWT(A)x=i=0kn1wx,iAi=i=0k1wx1,iFWT(Ai)x0

上面的定义和二进制类似,证明也类似,就直接写出来算了。(绝对不是因为懒

此时一样递归求就可以了。

矩阵就是下面的矩阵,其中 w k w_k wk 代表 k k k 下的单位根。(跟 FFT 里的矩阵一样)

[ 1 1 1 ⋯ 1 1 ω n 1 ω n 2 ⋯ ω n n − 1 1 ω n 2 ω n 4 ⋯ ω n 2 ( n − 1 ) ⋮ ⋮ ⋮ ⋱ ⋮ 1 ω n n − 1 ω n 2 ( n − 1 ) ⋯ ω n ( n − 1 ) ( n − 1 ) ] \left[ \begin{matrix} \ 1 & 1 & 1 & \cdots & 1 \ \\ \ 1 & \omega_n^1 & \omega_n^2 & \cdots & \omega_n^{n-1} \ \\ \ 1 & \omega_n^2 & \omega_n^4 & \cdots & \omega_n^{2(n-1)} \ \\ \ \vdots & \vdots & \vdots & \ddots & \vdots \ \\ \ 1 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \cdots & \omega_n^{(n-1)(n-1)} \ \end{matrix} \right]  1 1 1  11ωn1ωn2ωnn11ωn2ωn4ωn2(n1)1 ωnn1 ωn2(n1)  ωn(n1)(n1) 

可以看看代码加深理解!!!

代码

我这份代码是这道题的,三进制下的。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int n, k, len = 1;
LL ans;
complex<double> a[1000005];
const complex<double> w = { -0.5, 0.5 * sqrt(3) }, w2 = { -0.5, -0.5 * sqrt(3) };
int in() {char ch = getchar();int s = 0;while (ch < '0' || ch > '9') ch = getchar();while (ch <= '9' && ch >= '0') s = s * 3 + ch - '1', ch = getchar();return s;
}
void FWT(complex<double> *f, int flag) {for (int mid = 1; mid < len; mid = mid * 3) {for (int i = 0; i < len; i = i + mid * 3) {for (int j = i; j < i + mid; j++) {complex<double> t0 = f[j], t1 = f[j + mid], t2 = f[j + mid * 2];if (flag == 1) {f[j] = t0 + t1 + t2;f[j + mid] = t0 + t1 * w + t2 * w2;f[j + mid * 2] = t0 + t1 * w2 + t2 * w;} else {f[j] = t0 + t1 + t2;f[j + mid] = t0 + t1 * w2 + t2 * w;f[j + mid * 2] = t0 + t1 * w + t2 * w2;double t = f[j].real();f[j].real(t / 3);t = f[j + mid].real();f[j + mid].real(t / 3);t = f[j + mid * 2].real();f[j + mid * 2].real(t / 3);t = f[j].imag();f[j].imag(t / 3);t = f[j + mid].imag();f[j + mid].imag(t / 3);t = f[j + mid * 2].imag();f[j + mid * 2].imag(t / 3);}}}}
}
int main() {scanf("%d%d", &n, &k);for (int t = 0; t < k; t++) len = len * 3;for (int i = 0; i < n; i++) a[in()].real(1);FWT(a, 1);for (int i = 0; i < len; i++) a[i] = a[i] * a[i] * a[i];FWT(a, -1);ans = a[0].real() + 0.5;printf("%lld\n", (ans - n) / 6);return 0;
}

这篇关于k进制快速沃尔什变换(k进制FWT)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/178263

相关文章

MybatisX快速生成增删改查的方法示例

《MybatisX快速生成增删改查的方法示例》MybatisX是基于IDEA的MyBatis/MyBatis-Plus开发插件,本文主要介绍了MybatisX快速生成增删改查的方法示例,文中通过示例代... 目录1 安装2 基本功能2.1 XML跳转2.2 代码生成2.2.1 生成.xml中的sql语句头2

8种快速易用的Python Matplotlib数据可视化方法汇总(附源码)

《8种快速易用的PythonMatplotlib数据可视化方法汇总(附源码)》你是否曾经面对一堆复杂的数据,却不知道如何让它们变得直观易懂?别慌,Python的Matplotlib库是你数据可视化的... 目录引言1. 折线图(Line Plot)——趋势分析2. 柱状图(Bar Chart)——对比分析3

一文教你Java如何快速构建项目骨架

《一文教你Java如何快速构建项目骨架》在Java项目开发过程中,构建项目骨架是一项繁琐但又基础重要的工作,Java领域有许多代码生成工具可以帮助我们快速完成这一任务,下面就跟随小编一起来了解下... 目录一、代码生成工具概述常用 Java 代码生成工具简介代码生成工具的优势二、使用 MyBATis Gen

使用animation.css库快速实现CSS3旋转动画效果

《使用animation.css库快速实现CSS3旋转动画效果》随着Web技术的不断发展,动画效果已经成为了网页设计中不可或缺的一部分,本文将深入探讨animation.css的工作原理,如何使用以及... 目录1. css3动画技术简介2. animation.css库介绍2.1 animation.cs

C语言中的常见进制转换详解(从二进制到十六进制)

《C语言中的常见进制转换详解(从二进制到十六进制)》进制转换是计算机编程中的一个常见任务,特别是在处理低级别的数据操作时,C语言作为一门底层编程语言,在进制转换方面提供了灵活的操作方式,今天,我们将深... 目录1、进制基础2、C语言中的进制转换2.1 从十进制转换为其他进制十进制转二进制十进制转八进制十进

SpringBoot快速搭建TCP服务端和客户端全过程

《SpringBoot快速搭建TCP服务端和客户端全过程》:本文主要介绍SpringBoot快速搭建TCP服务端和客户端全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录TCPServerTCPClient总结由于工作需要,研究了SpringBoot搭建TCP通信的过程

一文教你Python如何快速精准抓取网页数据

《一文教你Python如何快速精准抓取网页数据》这篇文章主要为大家详细介绍了如何利用Python实现快速精准抓取网页数据,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录1. 准备工作2. 基础爬虫实现3. 高级功能扩展3.1 抓取文章详情3.2 保存数据到文件4. 完整示例

快速修复一个Panic的Linux内核的技巧

《快速修复一个Panic的Linux内核的技巧》Linux系统中运行了不当的mkinitcpio操作导致内核文件不能正常工作,重启的时候,内核启动中止于Panic状态,该怎么解决这个问题呢?下面我们就... 感谢China编程(www.chinasem.cn)网友 鸢一雨音 的投稿写这篇文章是有原因的。为了配置完

Python利用ElementTree实现快速解析XML文件

《Python利用ElementTree实现快速解析XML文件》ElementTree是Python标准库的一部分,而且是Python标准库中用于解析和操作XML数据的模块,下面小编就来和大家详细讲讲... 目录一、XML文件解析到底有多重要二、ElementTree快速入门1. 加载XML的两种方式2.

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指