FFT\NTT总结
学了好久,终于基本弄明白了
推荐两个博客:
戳我
戳我
再推荐几本书:
《ACM/ICPC算法基础训练教程》
《组合数学》(清华大学出版社)
《高中数学选修》
预备知识
复数方面
找数学老师去
\]
坐标系上纵轴就是虚数轴,复数就是这上面的点
三种表示法:
$$一般:a + bi,a为实部,b为虚部$$
$$指数:e^{i\theta}坐标系上的模长$$
$$三角:模长(cos\theta + i sin \theta)$$
运算:
加减法:实部虚部分别相加
乘法:$$(a + bi) * (c + di) = ac + adi + bci + bdi^{2}
= ac-bd+(ad+bc)i$$
欧拉公式
\]
\]
多项式
\]
\]
并且是唯一确定的\]
单位复数根
\]
三个性质:
消去引理:
$$n, d, k为正整数,则\omega{dk}_{dn}=\omega{k}{n}$$
$$证明:套e^{\frac{2k\pi i}{n}} 即可$$
折半引理:
$$n为大于零的偶数,则(\omega{k+\frac{n}{2}}_{n}){2}=\omega{2k+n}_{n}=\omega{2k}{n}\omega{n}_{n}=(\omega{k}{n})^{2}$$
求和引理:
大于1的整数n,和不被n整除的非负整数k,有
$$\Sigma{n-1}_{j=0}(\omega{k}{n})^{j}=0$$
证明可以用等比数列求和公式得到(很简单的,手推一遍就好)
Rader排序
其实就是二进制数位翻转
正题
DFT
对于k=0~n-1,定义:
\]
\]
逆DFT
\]
假设得到了向量y
\]
\]
\]
\]
FFT
上面已经把DFT和逆DFT搞定了,两个几乎是一样的
所以求多项式的积(卷积)可以用DFT转换成点值表示,就可以O(n),一一相乘,得到积的多项式的点值表示,最后用逆DFT得到系数表示
复杂度瓶颈在于怎样快速求解DFT(逆DFT和DFT方法一样)
FFT就是一个O(nlogn)求解DFT的方法
首先把A(x)分成奇数项和偶数项记作
\]
\]
\]
那么
\]
\]
\]
这称为蝴蝶操作
于是对每个y值的求解可以通过分组求出,若递归变成处理子任务,这样复杂度就成了O(nlogn)
这样不停地分组,最后就相当于Rader排序了一番,所以也可以变成非递归的
注意每次都要把多项式补成2的幂,便于FFT
递归写可能好理解一些,但不好写
还有一些东西什么的,其实记一记就好了其实自己说不清
系统的复数complex代码
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(3e6 + 10);
const double Pi = acos(-1);
IL ll Read(){
char c = '%'; ll x = 0, z = 1;
for(; c > '9' || c < '0'; c = getchar()) if(c == '-') z = -1;
for(; c >= '0' && c <= '9'; c = getchar()) x = x * 10 + c - '0';
return x * z;
}
int n, m, r[_], l;
complex <double> a[_], b[_];
IL void FFT(complex <double> *P, int opt){
for(RG int i = 0; i < n; ++i) if(i < r[i]) swap(P[i], P[r[i]]); //Rader排序
for(RG int i = 1; i < n; i <<= 1){
complex <double> W(cos(Pi / i), opt * sin(Pi / i)); //旋转因子
for(RG int p = i << 1, j = 0; j < n; j += p){
complex <double> w(1, 0);
for(RG int k = 0; k < i; ++k, w *= W){
complex <double> X = P[j + k], Y = w * P[j + k + i];
P[j + k] = X + Y; P[j + k + i] = X - Y; //蝴蝶操作
}
}
}
}
int main(RG int argc, RG char *argv[]){
n = Read(); m = Read();
for(RG int i = 0; i <= n; ++i) a[i] = Read();
for(RG int i = 0; i <= m; ++i) b[i] = Read();
m += n;
for(n = 1; n <= m; n <<= 1) ++l;//补成2的幂
for(RG int i = 0; i < n; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));//Rader排序预处理
FFT(a, 1); FFT(b, 1); //DFT
for(RG int i = 0; i < n; ++i) a[i] = a[i] * b[i]; //点值直接相乘
FFT(a, -1); //逆DFT
for(RG int i = 0; i <= m; ++i) printf("%d ", (int)(a[i].real() / n + 0.5));
return 0;
}
或者可以自己定义complex,用复数运算
struct Complex{
double real, image;
IL Complex(){ real = image = 0; }
IL Complex(RG double a, RG double b){ real = a; image = b; }
IL Complex operator +(RG Complex B){ return Complex(real + B.real, image + B.image); }
IL Complex operator -(RG Complex B){ return Complex(real - B.real, image - B.image); }
IL Complex operator *(RG Complex B){ return Complex(real * B.real - image * B.image, real * B.image + image * B.real); }
}
NTT(快速数论变换)
前置技能原根
设\(g\)为\(p\)(质数)的原根
则\(e^{\frac{2\pi i}{n}}\equiv\omega_n\equiv g^{\frac{p-1}{n}}(mod \ p)\)
带进去就好了
Reverse的那个不会证明
\(UOJ\)的模板
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int Zsy(998244353);
const int Phi(998244352);
const int G(3);
const int _(4e5 + 5);
IL ll Input(){
RG ll x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int n, m, N, l, r[_], A[_], B[_];
IL int Pow(RG ll x, RG ll y){
RG ll ret = 1;
for(; y; y >>= 1, x = x * x % Zsy)
if(y & 1) ret = ret * x % Zsy;
return ret;
}
IL void NTT(RG int *P, RG int opt){
for(RG int i = 0; i < N; ++i) if(r[i] < i) swap(P[r[i]], P[i]);
for(RG int i = 1; i < N; i <<= 1){
RG int W = Pow(G, Phi / (i << 1));
if(opt == -1) W = Pow(W, Zsy - 2);
for(RG int j = 0, p = i << 1; j < N; j += p){
RG int w = 1;
for(RG int k = 0; k < i; ++k, w = 1LL * w * W % Zsy){
RG int X = P[k + j], Y = 1LL * w * P[k + j + i] % Zsy;
P[k + j] = (X + Y) % Zsy, P[k + j + i] = (X - Y + Zsy) % Zsy;
}
}
}
}
int main(RG int argc, RG char* argv[]){
n = Input(), m = Input();
for(RG int i = 0; i <= n; ++i) A[i] = Input();
for(RG int i = 0; i <= m; ++i) B[i] = Input();
for(n += m, N = 1; N <= n; N <<= 1) ++l;
for(RG int i = 0; i < N; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
NTT(A, 1); NTT(B, 1);
for(RG int i = 0; i < N; ++i) A[i] = 1LL * A[i] * B[i] % Zsy;
NTT(A, -1);
RG int inv = Pow(N, Zsy - 2);
for(RG int i = 0; i <= n; ++i) printf("%lld ", 1LL * A[i] * inv % Zsy);
return 0;
}
FFT\NTT总结的更多相关文章
- FFT \ NTT总结(多项式的构造方法)
前言.FFT NTT 算法 网上有很多,这里不再赘述. 模板见我的代码库: FFT:戳我 NTT:戳我 正经向:FFT题目解题思路 \(FFT\)这个玩意不可能直接裸考的..... 其实一般\(FF ...
- [学习笔记&教程] 信号, 集合, 多项式, 以及各种卷积性变换 (FFT,NTT,FWT,FMT)
目录 信号, 集合, 多项式, 以及卷积性变换 卷积 卷积性变换 傅里叶变换与信号 引入: 信号分析 变换的基础: 复数 傅里叶变换 离散傅里叶变换 FFT 与多项式 \(n\) 次单位复根 消去引理 ...
- FFT/NTT/MTT学习笔记
FFT/NTT/MTT Tags:数学 作业部落 评论地址 前言 这是网上的优秀博客 并不建议初学者看我的博客,因为我也不是很了解FFT的具体原理 一.概述 两个多项式相乘,不用\(N^2\),通过\ ...
- FFT&NTT总结
FFT&NTT总结 一些概念 \(DFT:\)离散傅里叶变换\(\rightarrow O(n^2)\)计算多项式卷积 \(FFT:\)快速傅里叶变换\(\rightarrow O(nlogn ...
- 快速构造FFT/NTT
@(学习笔记)[FFT, NTT] 问题概述 给出两个次数为\(n\)的多项式\(A\)和\(B\), 要求在\(O(n \log n)\)内求出它们的卷积, 即对于结果\(C\)的每一项, 都有\[ ...
- FFT/NTT模板 既 HDU1402 A * B Problem Plus
@(学习笔记)[FFT, NTT] Problem Description Calculate A * B. Input Each line will contain two integers A a ...
- FFT/NTT基础题总结
在学各种数各种反演之前把以前做的$FFT$/$NTT$的题整理一遍 还请数论$dalao$口下留情 T1快速傅立叶之二 题目中要求求出 $c_k=\sum\limits_{i=k}^{n-1}a_i* ...
- $FFT/NTT/FWT$题单&简要题解
打算写一个多项式总结. 虽然自己菜得太真实了. 好像四级标题太小了,下次写博客的时候再考虑一下. 模板 \(FFT\)模板 #include <iostream> #include < ...
- FFT&NTT数学解释
FFT和NTT真是噩梦呢 既然被FFT和NTT坑够了,坑一下其他的人也未尝不可呢 前置知识 多项式基础知识 矩阵基础知识(之后会一直用矩阵表达) FFT:复数基础知识 NTT:模运算基础知识 单位根介 ...
- HDU-4609(FFT/NTT)
HDU-4609(FFT/NTT) 题意: 给出n个木棒,现从中不重复地选出3根来,求能拼出三角形的概率. 计算合法概率容易出现重复,所以建议计算不合法方案数 枚举选出的最大边是哪条,然后考虑剩下两条 ...
随机推荐
- 安装php的memcached模块和扩展支持sasl
memcached的1.2.4及以上增加了CAS(Check and Set)协议,对于同一key的多进行程的并发处理问题.这种情况其实根数据库很像,如果同时有几个进程对同一个表的同一数据进行更新的话 ...
- CentOS7 修改网卡名称为eth0
前言 无论是RHEL 7.还是CentOS 7都使用了NetworkManager.service来进行网络管理,当然network服务还是可以继续使用的,但也将会是过渡期的残留品了. 除此之外7版本 ...
- 在OS X系统中php访问sftp时需要ssh2扩展的安装
php -v brew install homebrew/php/php55-ssh2 [实现方式] <?php $connection = ssh2_connect('192.168.0.14 ...
- 图论算法-Tarjan模板 【缩点;割顶;双连通分量】
图论算法-Tarjan模板 [缩点:割顶:双连通分量] 为小伙伴们总结的Tarjan三大算法 Tarjan缩点(求强连通分量) int n; int low[100010],dfn[100010]; ...
- 剑指offer 丑数
思路:可以发现,每个丑数都是由以前的丑数得到.当前丑数一定是之前丑数能够得到的最小丑数. AC代码 class Solution { public: int GetUglyNumber_Solutio ...
- 2017第八届蓝桥杯 K倍区间
标题: k倍区间 给定一个长度为N的数列,A1, A2, - AN,如果其中一段连续的子序列Ai, Ai+1, - Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是K倍区间. ...
- 使用IntelliJ IDEA 和 Maven创建Java Web项目
1. Maven简介 相对于传统的项目,Maven 下管理和构建的项目真的非常好用和简单,所以这里也强调下,尽量使用此类工具进行项目构建, 它可以管理项目的整个生命周期. 可以通过其命令做所有相关的工 ...
- 关于使用srping @RequestParam 容易出错的地方
大家都知道,在spring中的@RequestParam主要用户传递参数用的,具体的解释就是将请求参数去数据映射到功能处理方法的参数上.其中包括三个参数: value:参数名字,即入参的请求参数名字, ...
- linux系统 initrd.img中init启动脚本分析
概述:这篇文章主体内容来源于网上转载.前面几篇文章倾向于制作initrd.img,这篇文章更倾向于initrd.img的运行过程:加载framebuff驱动 ide驱动和文件系统驱动,最后进入到真正的 ...
- 把mmapv1存储引擎存储的mongodb3.0数据库数据复制到WiredTiger存储引擎的mongodb3.2中
mongodb3.0在mmapv1的存储引擎基础上添加了一个新的存储引擎WiredTiger.但是3.0的默认存储引擎依旧是mmapv1,因此我们项目之前也就用的默认方式. 但是mongodb更新实在 ...