一、开头
(Place :山东省神犇协会第 998244353 会议厅)
SD 神犇 998244353 号(会长):所有神犇,洛谷黑题都切完了吗?
全体神犇:切完了!
神犇 1004535809 号: 998244353 ,我昨天看到一个弱鸡,洛谷名叫 xyz32768 ,他一道黑题都没做,您认为应该怎样呢?
神犇 998244353 号:这个问题您们考虑一下,应该用怎样的方式把 xyz32768 D 一遍。时刻记住,我们协会的口号:见一弱鸡, D 一弱鸡!
神犇 167772161 号:要不,考他 FFT 吧。这是我们协会里每个人都会的算法!
神犇 998244353 号:Good idea !
(Place : FFT 星球 DFT 国 IDFT 省 NTT 市)
神犇 167772161 号:哈哈,好久没见,我们搞 OI 多年,能回忆起的比赛,至少也从三年前的 SDOI 2015 开始吧,那次比赛有一道十分模板的题。题目名称:序列统计。题面你自己去 BZOJ 或洛谷上去查,如果你 1h 内写不出来我会对整个 FFT 星球说你菜!
xyz32768 :BZOJ 3992 / 洛谷 P3321 ?
神犇 1004535809 号:对。这是一道紫题,但此大佬已经将之视为宇宙之水题了。
(蒟蒻 xyz32768 当然不会,看了看算法标签)
xyz32768 : 什么?????? 快速傅里叶变换,DFT,FFT ??????
神犇 998244353 号:哈哈哈哈哈,你真是菜啊, FFT 这么水的算法都不会,再见蒟蒻!
神犇 998244353 号 & 神犇 1004535809 号 & 神犇 167772161 号(大声喊): xyz32768 菜, xyz32768 好菜, xyz32768 最菜!
二、预备知识
1、复数
下面的 i i ,除非作为
求和的变量,其余都表示虚数单位 −1−−−√ − 1 。
一个复数可以表示成 a+bi a + b i 的形式,也可以表示成 r(cosθ+isinθ) r ( cos θ + i sin θ ) 的形式。
上面 a a 为实部,
为虚部, r=a2+b2−−−−−−√ r = a 2 + b 2 为模长, θ=arctanba θ = arctan b a 为辐角。
C++ 中,
#include <bits/stdc++.h>
using namespace std;
复数类为( T 为实部和虚部的数据类型):
complex<T>
定义一个复数( a a 为实部, 为虚部)
complex <T> x(a, b)
实部
x.real()
一个复数 a+bi a + b i 对应复平面上一个点 (a,b) ( a , b ) ,模长 r r 为点到原点的距离,辐角 为终边为 (0,0)−(a,b) ( 0 , 0 ) − ( a , b ) 的角(即该边与 x 轴正半轴形成的角)。
2、单位根
那么
如:
n n 次单位根的性质 :
(1) 次单位根所表示的点分布在复平面的单位圆上,并且把圆周等分成 n n 段。
(2) 次单位根的 n n 次方等于 。
(3)
3、原根
在模 p p (为质数)意义下,如果存在数
,满足
互不相同,那么 g g 为模 的原根。
原根都比较小,可以暴力枚举。将 p−1 p − 1 分解质因数,对于一个 g g ,如果对于 的任何一个质因子 x x ,都有
那么 g g 是模 的一个原根。
三、多项式乘法
步入正题。一个 n n 次多项式
和一个 n n 次多项式
相乘,设 A A 的系数为
( xi x i 的项系数为 ai a i ), B B 的系数为
,那么
复杂度显然是 O(n2) O ( n 2 ) 的。快速傅里叶变换( FFT )则能做到 O(nlogn) O ( n log n ) 的复杂度。
四、多项式的点值表示及 DFT
多项式的点值表示:选取 n+1 n + 1 个互不相同的值 x0...n x 0... n 代入 A A 对多项式进行求值,得到 个多项式值,那么这 n+1 n + 1 个自变量和这 n+1