感觉上前置知识是毛啸 16 年的论文?

我手头也有,到时候发现有 at 到的地方就插一嘴说一句

srds 先这篇是因为有纸质版的这篇

感觉上大篇幅在讲复杂度模数大小相关的做法。

1 引言

我这写个啥?

概括一下。FFT nb,但是光会板子不够,给你整点有用的新玩意。我先扯点别人写过的,再给你讲讲任意长度 FFT。

反正不要钱,多少看一点~

2 定义及说明

2.1 约定

  1. \(|f(x)| :=\) 多项式 \(f\) 的次数/系数。
  2. \(f(p) :=\) 多项式 \(f(x)\) 在 \(p\) 处的点值。
  3. \(\omega_n :=\) \(n\) 次单位根,即 \(\cos\left(\frac {2\pi} n\right) + \sin\left(\frac {2\pi} n\right)i\)。
  4. \(DFT(f):=\) 多项式 \(f(x)\) 在进行 DFT 后得到的系数序列。
  5. \(f_i :=\) 多项式 \(f(x)\) 的第 \(i\) 项系数。一般地,\(0\le i < |f(x)|\)。

2.2 DFT

离散傅里叶变换(DFT)是将 \(\omega_n^0,\omega_n^1,\cdots,\omega_n^{n-1}\) 依次带入多项式 \(f(x)\) 中得到的长度为 \(n\) 的点值序列 \(a\)。称 \(n = 2^k\) 为模长。一般有 \(n > |f(x)|\)。

在已知长度为 \(n\) 的多项式 \(f(x)\) 的点值序列 \(a\) 的情况下,我们构造多项式 \(g(x) = \sum_{i=0}^{n-1} a_i x^i\),并求出依次将 \(\omega_n^0, \omega_n^{-1},\cdots,\omega_{n}^{-(n-1)}\) 带入得到的点值序列 \(b\),则 \(f(x) = \frac 1n\sum_{i=0}^{n-1} b_i x^i\)。

证明:

\[\begin{aligned}

b_k &= \ \sum_{i=0}^{n-1} a_i\left(\omega_n^{-k}\right)^i
\\ & = \ \sum_{i=0}^{n-1} \left(\sum_{j=0}^{n-1} f_i\left(\omega_n^i\right)^j \right)\left(\omega_n^{-k}\right)^i
\\ & = \ \sum_{i=0}^{n-1} f_i\left(\sum_{j=0}^{n-1} \left(\omega_n^{i-k}\right)^j \right)
\\ & = \ \sum_{i=0}^{n-1} f_i\times n[i - k = 0]
\\ & = \ n f_k

\end{aligned}\]

\(3\to 4\) 的转化考虑 \(i-k=0\) 时 \(\omega_{n}^{i-k} = 1\),反之通过等比数列求和得到总和为 \(0\)。

2.3 MTT

为啥它会把一般模数 FFT 叫做 MTT 呢?

首先有一种拆系数 FFT。

假设我们需要求解 \(A(x)\times B(x)\) 的各项系数对 \(1e9 + 7\) 等模数取模后的值。如果直接干上去,运行多项式乘积时产生值的绝对值是 \(O(p^2|A(x)|)\) 的,不能接受。

我们将多项式的各项系数写作 \(xC + y(0\le y < C)\) 的形式,其中 \(C\) 是一个正整数。那写 \(A(x) = CA_1(x) + A_2(x)\),\(B(x) = CB_1(x) + B_2(x)\)。则

\[A(x)\times B(x) = C^2 A_1(x)B_1(x) + CA_1(x) B_2(x) + CA_2(x) B_1(x) + A_2(x)B_2(x)
\]

我们取 \(C = \left\lfloor \sqrt p\right\rfloor\),则运行多项式乘积时产生值的绝对值是 \(O(p|A(x)|)\) 的,可以接受。

然后说一下三次变两次的优化。srds这部分论文里没有

就是说啊,我们构造多项式 \(P(x) = A(x) + B(x)i,\ Q(x) = A(x) - B(x)i\),则根据定义由 \(DFT(A)_ i = \frac{DFT(P)_ i + DFT(Q)_ i}2,\ DFT(B)_ i = -i \frac{DFT(P)_ i - DFT(Q)_ i}2\)。并且,我们有 \(DFT(P)_ i = DFT(Q)_ {n-i}\)。证明考虑在写出 \(DFT(Q)_ i\) 的表式时展开两个复数的相乘部分,并取共轭。

容易发现这样只需要两次 \(DFT\),分别是取得 \(DFT(P),\ DFT(Q)\) 和 \(A(x)\times B(x)\)。

然后通过这样的优化,我们能得到一种四次 DFT 的 MTT 写法。这里有一份常数不大的实现。

其次有一种做两/三次 NNT 模数下的 DFT 后使用 CRT 合并的写法。常数太大了,没人写。

3 任意模长 DFT

3.1 引入

例题 1:单位根反演练习题。

\[\sum_{i=0}^{\infty}\binom{k}{in+m} = \sum_{i=0}^{k}\binom{k}{i}[n | i - m] = \sum_{i=0}^k\binom ki \frac 1n\sum_{j=0}^{n-1}\omega_{n}^{(i-m)j}
\]

例题 2:【模板】Chirp Z-Transform

没讲做法。因为下面:

3.2 快速傅里叶变换

讲了一下 FFT 的基础分治部分。为下面做准备用的。

具体内容左转oiwiki

3.3 基于分治的快速傅里叶变换

类比 FFT,我们推广。一般地,我们需要计算 \(V(j) = \sum_{i=0}^{n-1} a_i \omega_n^{ij}\)。

仍然是拆 \(n\)。设 \(n\) 的 \(lpf\) 为 \(d\),我们有这样的做法的复杂度为 \(T(n) = dT(\frac nd) + O(dn)\)。容易看出来 \(T(n) = O(n^2)\)。

换种做法。

3.4 基于卷积的快速傅里叶变换

嗯,正主来了。Chirp Z-Transform,简称 czt。又称 Z 算法、bluestein 算法。

套路地,\(ij = \binom{i + j}2 - \binom i2 - \binom j2\)。

对于 \(DFT\),我们有式子

\[V(j) \omega_n^{\binom j2} = \sum_{i = 0}^{n-1} a_i\omega_n^{-\binom{i}{2}}\omega_n^{\binom{i + j}{2}}
\]

等号右侧可以看作构造多项式 \(F(x) = \sum_{i=0}^{n-1} \omega_n^{-\binom{i}{2}}x^i\) 对 \(G(x) = \sum_{i=0}^{n-1}\omega_n^{a_i\binom{i}{2}}x^i\) 进行了减卷积后的结果。然后右侧的部分不需要模长的限制,可以直接做不限制长度的 DFT。

对于 \(IDFT\),我们有式子

\[V(j) \omega_n^{-\binom j2} = \sum_{i = 0}^{n-1} a_i\omega_n^{\binom{i}{2}}\omega_n^{-\binom{i + j}{2}}
\]

直接减卷积即可。

总时间复杂度 \(O(n\log n)\)。

code
signed main() {
ios::sync_with_stdio(false), cout.tie(0);
get(n, c, m); int inv = qp(c, mod - 2);
for (int i = 0, p1 = 1, p2 = 1; i < n; ++ i) {
get(a[n - i - 1]);
a[n - i - 1] = 1ll * a[n - i - 1] * p1 % mod;
if (i) p2 = 1ll * p2 * inv % mod, p1 = 1ll * p1 * p2 % mod;
}
for (int i = 0, p1 = 1, p2 = 1; i < n + m; ++ i) {
b[i] = p1;
if (i) p2 = 1ll * p2 * c % mod, p1 = 1ll * p1 * p2 % mod;
}
poly f(a, a + n), g(b, b + n + m);
f = f * g;
for (int i = 0, p1 = 1, p2 = 1; i < m; ++ i) {
cout << 1ll * f[i + n - 1] * p1 % mod << ' ';
if (i) p2 = 1ll * p2 * inv % mod, p1 = 1ll * p1 * p2 % mod;
}
}

优化技巧:减卷积,模长需要开到 \(3n\) 级别,但是我们只需要中间 \(n\) 个元素。因此开 \(2n\) 长度就够了。

事实上,对于任意的非零数字 \(a\),我们都可以通过此类思路来计算 \(V(j) = \sum_{i=0}^{n-1} x_i a^{ij}\)(此处的上下标问题存疑)的值。我们只需要保证存在 \(a^{ij}\) 及其逆元即可。也就是说,对于任意复数该算法仍然适用。这点在下方有实际应用。

3.5 例题

略(

U498 新年的追逐战

CF901E Cyclic Cipher

4 多点求值

4.1 思路

大家都知道多项式多点求值是啥了,我就不说了。

由于 DFT 是将一系列点值 \(\omega_n^i\) 依次带入 \(f(x)\) 得到的长度为 \(n\) 的点值序列,因此在解决一类点值有特殊性质的多点求值问题时,我们可以将点值重排列后使用 czt 加速多点求值的进程。

例题:点值性质相关多点求值

给一个多项式 \(f(x)\)。\(q\) 次询问,第 \(i\) 次询问 \(f(q_i)\) 对 \(p = 998244353\) 取模后的结果。对于 \(q_i\),我们按 \(q_i = aq_{i-1} + b\) 生成。

做法:

假设我们已知了 \(f(x)\)。则我们可以在 \(O(|f(x)|)\) 的复杂度内找到唯一一个次数不超过 \(|f(x)|\) 的多项式 \(g(x)\) 满足 \(g(x) = f(x \times k)\),也可以在 \(O(|f(x)|\log |f(x)|)\) 的复杂度内找到唯一一个次数不超过 \(|f(x)|\) 的多项式 \(g(x)\) 满足 \(g(x) = f(x + k)\)。

归纳得到 \(q_i = q_0a^i + \sum_{j=0}^{i-1} ba^j\)。乘 \((a-1)\) 再加 \(b\),再除 \(q_0(a - 1) + b\)。推一下式子你会发现这个过程就是在将等号右侧消成单纯的 \(a^i\)。

因此构造 \(g(x) = f(\frac{x(q_0(a - 1) + b) - b}{a - 1})\)。我们只需要求得 \(\forall\ 1\le i \le q,\ g(a^i)\) 的点值,即求解 \(V(j) = \sum_{i=0}^{n-1} g_ia^{ij}\)。使用 czt 求解即可。

总时间复杂度 \(O((n+q)\log (n+q))\)。

例题:模数值域相关多点求值

给一个多项式 \(f(x)\)。\(q\) 次询问,每次询问给定 \(y\),求 \(f(y)\) 对 \(p = 786433(3\times 2^{18} + 1)\) 取模的值。\(0\le y < p\)。

做法:

考虑 DFT 是个啥。其实就是把 \(\omega_n^i\) 分别带入 \(f(x)\) 后的点值。

因为 \(p\) 是质数,因此其存在一个原根 \(g\)。同时不难发现 \(g^0,g^1,\cdots,g^{n-2}\) 在模 \(p\) 意义下互不相同,且组成了一个 \(1\sim p-1\) 的排列。

因此对 \(f\) 进行长度为 \(p-1\) 的定长度 DFT,取各位点值重排后即可得到所有可能的询问的答案。\(0\) 处的点值显然是 \(DFT(f)_ 0\)。

总时间复杂度 \(O(p\log p)\)。

4.2 推广

模数值域相关多点求值的模数其实可以被推广到 \(p = q^c\),其中 \(q\) 是奇质数。由于 \(p\) 存在原根 \(g\),因此任意 \((y,p) = 1\) 的询问 \(y\) 都可以经一次定长度 DFT 求得。现在考虑 \((y,p) \neq 1\) 的情况。显然 \(y^c \equiv 0 \pmod p\)。因此我们对于这类值只需要考虑小于 \(c\) 的项的贡献。因此直接暴力计算前 \(c\) 项即可。由于 \(c = O(\log p)\),因此这部分的总时间复杂度为 \(O(p \log p)\)。

因此总时间复杂度 \(O(p\log p)\)。

特殊的,对于 \(p = 2^c\) 的特殊模数,虽然没原根了,但是论文里说能证明 \(\pm 3^0, \pm 3^1, \cdots, \pm3^{2^{c-2}}\) 各项在模意义下彼此不同且与 \(2\) 互质。然后总时间复杂度仍然是 \(O(p\log p)\) 的。一堆奇怪的 corner cases,但是我不是很认为有人会闲的出自己论文里的这种分讨题。所以没有应用,就这样吧。

这同样表示我们可以通过 CRT 合并答案,因此能做到 \(O(p\log p)\) (复杂度存疑)进行任意模数多项式多点求值。

多项式多点插值

由于 DFT 能在多点求值问题上获得很好的应用,我们可以考虑将 IDFT 应用到多点求值的逆运算多点插值上。

5.1 连续点值的多点插值

对。给 \(0\le i < n\) 的 \(f(i)\),求 \(f(x)\) 的系数模 \(p\) 意义下的值。\(p\le 5\times 10^5\),\(p\) 是质数。

首先点值形式转下降幂形式。然后计算 \(0\sim p-1\) 处的点值。随后我们可以通过一次定长度 IDFT 取得一个多项式 \(g(x)\)。构造 \(h(x) \equiv [x = 0]\pmod p\),容易(?)发现 \(f(x) = g(x) + h(x)(a_0 - g(0))\)。

这里的多项式 \(h(x)\) 可以构造为 \(\sum_{i=0}^{p-2}x^i\)。总时间复杂度 \(O(p\log p)\)。

5.1 非连续点值的多点插值

对。给 \(0\le i < n\) 的 \(f(a_i)\),求 \(f(x)\) 的系数模 \(p\) 意义下的值。\(p\le 3\times 10^5\),\(p\) 是质数。

上来先插一波。

\[f(x) = \sum_{i=1}^n f(a_i) \prod_{j\neq i} \frac {x - a_j}{a_i - a_j}
\]

设 \(g(x) = \prod{i=1}^n (x - a_i)\)。则 \(f(x) = g(x)\sum_{i=1}^n \frac{f(a_i)}{(x - a_i) g'(a_i)}\)。

首先是 \(g(x)\) 怎么求。你当然可以直接分治求,总时间复杂度是 \(O(n\log^2 n)\) 的。

但是两边除以 \(\prod -a_i\),再取 \(\ln\) 并求导后得到

\[\ln' \left(\frac{g(x)}{\prod -a_i}\right) = \sum_i \sum_j x^j \frac 1{a_i ^{j+1}}
\]

复杂度 \(O(p \log p)\)。

然后是形如 \(F(x) = \sum_{i}\frac{v_i}{x - a_i}\) 的式子怎么求。这法子挺高级的。

\[\begin{aligned}

F(x) & = \ \sum_{i}\frac{v_i}{x - a_i}
\\ & = \ \sum_{i} v_i \sum_{j} x^j \left(\frac 1 {a_i}\right)^{j+1}
\\ & = \ \sum_{j} x^j \sum_{i} v_i \left(\frac 1 {a_i}\right)^{j+1}
\\ & = \ \sum_{j} x^j \sum_{i} \sum_{k} v_i \omega_{p-1}^{-k(j+1)}[\omega_{p-1}^k ={a_i}]
\\ & = \ \sum_{j} x^j \sum_{k} \sum_{i} v_i[\omega_{p-1}^k ={a_i}] \omega_{p-1}^{-k(j+1)}

\end{aligned}\]

设 \(G(k) = \sum_{i} v_i[\omega_{p-1}^k ={a_i}]\)。

\[\begin{aligned}

F(x) & = \ \sum_{j} x^j \sum_{k} \sum_{i} v_i[\omega_{p-1}^k ={a_i}] \omega_{p-1}^{-k(j+1)}
\\ & = \ \sum_{j} x^j \sum_{k} G(k) \omega_{p-1}^{-k(j+1)}
\\ & = \ x^{-1} \sum_{j} x^j \sum_{k} G(k) \omega_{p-1}^{-kj}

\end{aligned}\]

最后的式子的右半边两个求和号很符合 czt。算出 \(G\) 的点值后可以直接 \(O(p\log p)\)。

最后只需要将 \(g\) 求导后多点求值。

容易做到 \(O(p\log p)\)。

当然,上面的推导用到了 \(\frac 1x\) 和求导,因此在 \(a_i = 0\) 的情况下会产生错误。可以构造 \(g(x) = f(x + k)\) 使得点值非 \(0\),算完平移回来就好了。另一种方法是忽略 \(a_i = 0\) 处的点值,最后加入 \(k\prod_{a_i \neq 0}(x - a_i)\) 调整 \(f(0)\) 处的点值。第二种方法也被称作部分拉格朗日插值。

上面求 \(F(x)\) 的方法等价于给定一个列向量,左乘一个 Vandermonde 矩阵。因此我们也可以将上述算法用于解 Vandermonde 矩阵。

设我们需要解 \(F(i) = \sum_{j}a_jx_j^i\)。仍然设 \(G(x) = \sum_{i} [\omega_{p-1}^k = x_i]v_i\)。方程组转化成解 \(F(i) = \sum_{i} G(i) \omega_{p-1}^{ij}\)。不难发现这是 czt 形式。解决该问题需要 \(O(p \log p)\) 的时间复杂度。

03 年提出了一个 iczt。

感谢大家的阅读!没了!

《不一般的 DFT》阅读随笔的更多相关文章

  1. 浅谈左偏树在OI中的应用

    Preface 可并堆,一个听起来很NB的数据结构,实际上比一般的堆就多了一个合并的操作. 考虑一般的堆合并时,当我们合并时只能暴力把一个堆里的元素一个一个插入另一个堆里,这样复杂度将达到\(\log ...

  2. 浅谈算法和数据结构: 七 二叉查找树 八 平衡查找树之2-3树 九 平衡查找树之红黑树 十 平衡查找树之B树

    http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html 前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的 ...

  3. 【ASP.NET MVC系列】浅谈jqGrid 在ASP.NET MVC中增删改查

    ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...

  4. 浅谈算法和数据结构: 十 平衡查找树之B树

    前面讲解了平衡查找树中的2-3树以及其实现红黑树.2-3树种,一个节点最多有2个key,而红黑树则使用染色的方式来标识这两个key. 维基百科对B树的定义为“在计算机科学中,B树(B-tree)是一种 ...

  5. 转 浅谈算法和数据结构: 十 平衡查找树之B树

    前面讲解了平衡查找树中的2-3树以及其实现红黑树.2-3树种,一个节点最多有2个key,而红黑树则使用染色的方式来标识这两个key. 维基百科对B树的定义为"在计算机科学中,B树(B-tre ...

  6. 【ASP.NET 系列】浅谈缓存技术在ASP.NET中的运用

    本篇文章虽不谈架构,但是Cache又是架构中不可或缺的部分,因此,在讲解Cache的同时,将会提及到部分架构知识,关于架构部分,读者可以不用理解,或者直接跳过涉及架构部分的内容 你只需关心Cache即 ...

  7. 浅谈缓存技术在ASP.NET中的运用

    本篇文章虽不谈架构,但是Cache又是架构中不可或缺的部分,因此,在讲解Cache的同时,将会提及到部分架构知识,关于架构部分,读者可以不用理解,或者直接跳过, 你只需关心Cache即可,具体的架构, ...

  8. Talk About AWS Aurora for MySQL max_connections parameter Calculation | 浅谈AWS Aurora for MySQL数据库中 max_connections参数的计算

    1. The Problem | 现象 When connect to the product environment database of my company, the Navicat show ...

  9. 浅谈DevExpress<三>:在GridView中加载动态图片

    今天的演示效果如下:在GridView中的下拉框中选中一种颜色,则后面的加载相应的图片,如下图: 1.

  10. 浅谈利用同步机制解决Java中的线程安全问题

    我们知道大多数程序都不会是单线程程序,单线程程序的功能非常有限,我们假设一下所有的程序都是单线程程序,那么会带来怎样的结果呢?假如淘宝是单线程程序,一直都只能一个一个用户去访问,你要在网上买东西还得等 ...

随机推荐

  1. 【学习笔记】 第04章 NumPy基础:数组和矢量计算

    前言 正式开始学习Numpy,参考用书是<用Python进行数据清洗>,计划本周五之前把本书读完,关键代码全部实现一遍 NumPy基础:数组和矢量计算 按照书中所示,要搞明白具体的性能差距 ...

  2. 4.第三篇 PKI基础概念、cfssl工具介绍及kubernetes中证书

    文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247483787&idx=1&sn=08dd3404 ...

  3. 初试 Centos7 上 Ceph 存储集群搭建

    转载自:https://cloud.tencent.com/developer/article/1010539 1.Ceph 介绍 Ceph 是一个开源的分布式存储系统,包括对象存储.块设备.文件系统 ...

  4. 复现禅道V16.5的SQL注入(CNVD-2022-42853)

    漏洞详情 禅道V16.5未对输入的account参数内容作过滤校验,导致攻击者拼接恶意SQL语句执行. 环境搭建 环境下载:禅道V16.5 下载后双击运行,进入目录运行start.exe 直接访问即可 ...

  5. 30分钟掌握 Webpack

    本文基于:峰华前端工程师--30分钟掌握Webpack 为什么使用 Webpack 在我们进行传统网页开发中,会在 index.html 中引入大量的 js 和 css 文件,不仅可能会导致命名冲突, ...

  6. 线程池底层原理详解与源码分析(补充部分---ScheduledThreadPoolExecutor类分析)

    [1]前言 本篇幅是对 线程池底层原理详解与源码分析  的补充,默认你已经看完了上一篇对ThreadPoolExecutor类有了足够的了解. [2]ScheduledThreadPoolExecut ...

  7. WSL 2 上启用微软官方支持的 systemd

    以前折腾了很久的 genie 和 distrod 来实现 wsl2 上的 systemd.现在微软和Canonical联合声明发布了官方支持的systemd,之前的折腾貌似有点浪费时间了.如果微软不发 ...

  8. bfs与dfs基础

    bfs像二叉树的层序遍历 像这个图走bfs就{1, 2, 3, 4, 5, 6, 7, 8}这样走: dfs就{1, 2, 5, 6, 3, 7, 8, 4}. bfs与queue相结合,走到哪就把哪 ...

  9. Java代码审计之实战某博客

    对某博客的代码审计 在gitee上面找了一个个人博客项目,来进行实战代码审计,主要还是学习为主 技术菜菜,哪里错误希望师傅们指正 1.SQL注入 先了解Java Web中的数据传输流程 graph T ...

  10. React魔法堂:echarts-for-react源码略读

    前言 在当前工业4.0和智能制造的产业升级浪潮当中,智慧大屏无疑是展示企业IT成果的最有效方式之一.然而其背后怎么能缺少ECharts的身影呢?对于React应用而言,直接使用ECharts并不是最高 ...