$FFT$好美啊


参考资料:

1.算法导论 2.Miskcoo 3.Menci 4.虚数的意义-阮一峰


简单说一下,具体在下面的图片

实现:

可以用$complex$也可以手写 和计算几何差不多 注意$complex*complex$

$omega[k]=w(n,k)$  $omegaInv[k]=w(n,-k)$是共轭复数 先预处理 递推可能有精度问题

$transform$

  • 先把位置弄好了,方法是直接求二进制逆序,单向交换
  • 然后枚举$l$为当前合并后的长度,$m=l>>1$就是当前要合并的两段的长度,$p$枚举位置,蝴蝶变化,指针就是喵啊
  • $[p,p+m)$保存了$A_0$,$[p+m,p+l)$保存了$A_1$,然后就是利用了$A(x)=A_0(x^2)+x*A_1(x^2)$

$FFT$要先加倍次数界

const double PI=acos(-);
struct Vector{
double x,y;
Vector(double a=,double b=):x(a),y(b){}
};
typedef Vector CD;
Vector operator +(Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
Vector operator -(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
Vector operator *(Vector a,Vector b){return Vector(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
Vector conj(Vector a){return Vector(a.x,-a.y);} struct FastFourierTransform{
int n,rev[N];
CD omega[N],omegaInv[N];
void ini(int m){
n=;
while(n<m) n<<=;
for(int k=;k<n;k++)
omega[k]=CD(cos(*PI/n*k),sin(*PI/n*k)),
omegaInv[k]=conj(omega[k]); int k=;
while((<<k)<n) k++;
for(int i=;i<n;i++){
int t=;
for(int j=;j<k;j++) if(i&(<<j)) t|=(<<(k-j-));
rev[i]=t;
}
}
void transform(CD *a,CD *omega){
for(int i=;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int l=;l<=n;l<<=){
int m=l>>;
for(CD *p=a;p!=a+n;p+=l)
for(int k=;k<m;k++){
CD t=omega[n/l*k]*p[k+m];
p[k+m]=p[k]-t;
p[k]=p[k]+t;
}
}
}
void DFT(CD *a,int flag){
if(flag==) transform(a,omega);
else{
transform(a,omegaInv);
for(int i=;i<n;i++) a[i].x/=(double)n;
}
}
}fft;

FFT模板

每次递推$w$会更快

长度枚举到$l$时 $w_n=e^{\frac{2\pi}{i}}$

const double PI=acos(-);
struct Vector{
double x,y;
Vector(double a=,double b=):x(a),y(b){}
};
typedef Vector CD;
Vector operator +(Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
Vector operator -(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
Vector operator *(Vector a,Vector b){return Vector(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);} struct FastFourierTransform{
int n,rev[N];
void ini(int m){
n=;
while(n<m) n<<=; int k=;
while((<<k)<n) k++;
for(int i=;i<n;i++){
int t=;
for(int j=;j<k;j++) if(i&(<<j)) t|=(<<(k-j-));
rev[i]=t;
}
}
void DFT(CD *a,int flag){
for(int i=;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int l=;l<=n;l<<=){
int m=l>>;
CD wn(cos(*PI/l),flag*sin(*PI/l));
for(CD *p=a;p!=a+n;p+=l){
CD w(,);
for(int k=;k<m;k++){
CD t=w*p[k+m];
p[k+m]=p[k]-t;
p[k]=p[k]+t;
w=w*wn;
}
}
}
if(flag==-) for(int i=;i<n;i++) a[i].x/=n;
}
}fft;

FFT模板2


卷积 $(f \times g)(n)=\sum\limits_{i=0}^{n}{f(i)*g(n-i)}$

多项式乘法就是一个系数向量的卷积

可以用$FFT$快速计算卷积

遇到和不是定值的情况可以反转一个向量



本来是另一篇博客,搬到这里来了

参考资料

http://blog.miskcoo.com/2015/04/polynomial-multiplication-and-fast-fourier-transform#i-13

https://oi.men.ci/fft-to-ntt/

http://blog.csdn.net/acdreamers/article/details/8883285


目的:

1.只有整数参与时防止浮点误差(我做题少,还没遇到误差......)

2.题目要求模意义下


:设,使得成立的最小,称为对模的阶,记为

原根:是正整数,是整数,若的阶等于,则称为模的一个原根。

假设一个数对于模(p is prime)来说是原根,那么结果互不相同,那么是模的一个原根;

因为当且仅当指数为的时候成立,所以不可能相同啊。

有原根的充要条件:

,其中是奇素数。

求模素数原根的方法:

枚举g,对素因子分解,即的标准分解式,若恒有成立,则就是的原根。(对于合数求原根,只需把换成即可)

实现:

PrimitiveRoot

当然了,在NNT中为了简单起见不要筛素数了,直接枚举p-1的所有约数就行了

ll powMod(ll a,ll b,ll MOD){
ll ans=1;
for(;b;b>>=1,a=a*a%MOD)
if(b&1) ans=ans*a%MOD;
return ans;
}
int PrimitiveRoot(int p){
if(p==2) return 1;
for(int g=2;g<p;g++){
int flag=1,m=sqrt(p);
for(int i=2;i<=m;i++) if((p-1)%i==0)
if(powMod(g,(p-1)/i,p)==1) {flag=0;break;}
if(flag) return g;
}
return 0;
}

NNT ---Fast Number-Theoretic Transform

质数p=q*n+1 (n=2m)  原根g  则gqn Ξ 1 (mod p)

看成是的等价

令gΞ gq (mod p)     即wn的等价

  • gn0,1,...,n-1  (mod p) 互不相同
  • gn^n Ξ 1 (mod p)   则 gn^n/2 Ξ -1 (mod p)  ,因为互不相同所以不能是1
  • 其他wn的性质也满足

所以可以用原根代替单位根

这里的n(用N表示吧)可以比原来那个的n(乘法结果的长度扩展到2的幂次后的n)大,只要把q*N/n看做q就行了

 

枚举到l长度时wn就是g(p-1)/l

通常P和g是固定的,提前处理出来就行了  一个很好的选择是 1004535809=479⋅221+1

ll P=1004535809,MOD=P;
ll Pow(ll a,ll b,ll MOD){
ll ans=1;
for(;b;b>>=1,a=a*a%MOD)
if(b&1) ans=ans*a%MOD;
return ans;
}
struct NumberTheoreticTransform{
int n,rev[N];
ll g;
void ini(int m){
n=1;
while(n<m) n<<=1; int k=0;
while((1<<k)<n) k++;
for(int i=0;i<n;i++){
int t=0;
for(int j=0;j<k;j++) if(i&(1<<j)) t|=(1<<(k-j-1));
rev[i]=t;
} g=3;
}
void DFT(ll *a,int flag){
for(int i=0;i<n;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int l=2;l<=n;l<<=1){
int m=l>>1;
ll wn=Pow(g,flag==1?(P-1)/l:P-1-(P-1)/l,P);
for(ll *p=a;p!=a+n;p+=l){
ll w=1;
for(int k=0;k<m;k++){
ll t=w*p[k+m]%P;
p[k+m]=(p[k]-t+P)%P;
p[k]=(p[k]+t)%P;
w=w*wn%P;
}
}
}
if(flag==-1){
ll inv=Pow(n,P-2,P);;
for(int i=0;i<n;i++) a[i]=a[i]*inv%P;
}
}
void MUL(ll *A,ll *B){
DFT(A,1);DFT(B,1);
for(int i=0;i<n;i++) A[i]=A[i]*B[i]%MOD;
DFT(A,-1);
}
}fft;

[快速傅立叶变换&快速傅里叶变换]【旧 手写笔记】的更多相关文章

  1. 为什么要进行傅立叶变换?傅立叶变换究竟有何意义?如何用Matlab实现快速傅立叶变换

    写在最前面:本文是我阅读了多篇相关文章后对它们进行分析重组整合而得,绝大部分内容非我所原创.在此向多位原创作者致敬!!!一.傅立叶变换的由来关于傅立叶变换,无论是书本还是在网上可以很容易找到关于傅立叶 ...

  2. 离散傅立叶变换与快速傅立叶变换(DFT与FFT)

    自从去年下半年接触三维重构以来,听得最多的词就是傅立叶变换,后来了解到这个变换在图像处理里面也是重点中的重点. 本身自己基于高数知识的理解是傅立叶变换是将一个函数变为一堆正余弦函数的和的变换.而图像处 ...

  3. $\mathcal{FFT}$·$\mathcal{Fast \ \ Fourier \ \ Transformation}$快速傅立叶变换

    \(2019.2.18upd:\) \(LINK\) 之前写的比较适合未接触FFT的人阅读--但是有几个地方出了错,大家可以找一下233 啊-本来觉得这是个比较良心的算法没想到这么抽搐这个算法真是将一 ...

  4. 快速傅立叶变换(FFT)算法

    已知多项式f(x)=a0+a1x+a2x2+...+am-1xm-1, g(x)=b0+b1x+b2x2+...+bn-1xn-1.利用卷积的蛮力算法,得到h(x)=f(x)g(x),这一过程的时间复 ...

  5. BZOJ 2194 快速傅立叶变换之二 | FFT

    BZOJ 2194 快速傅立叶变换之二 题意 给出两个长为\(n\)的数组\(a\)和\(b\),\(c_k = \sum_{i = k}^{n - 1} a[i] * b[i - k]\). 题解 ...

  6. 快速傅立叶变换(FFT)

    多项式 系数表示法 设\(f(x)\)为一个\(n-1\)次多项式,则 \(f(x)=\sum\limits_{i=0}^{n-1}a_i*x_i\) 其中\(a_i\)为\(f(x)\)的系数,用这 ...

  7. NVIDIA GPU的快速傅立叶变换

    NVIDIA GPU的快速傅立叶变换 cuFFT库提供GPU加速的FFT实现,其执行速度比仅CPU的替代方案快10倍.cuFFT用于构建跨学科的商业和研究应用程序,例如深度学习,计算机视觉,计算物理, ...

  8. 手写笔记变PDF-几行代码变命令行程序为图形化界面

    前言 最近发现了一个非常不错的Python类库----Gooey, https://github.com/chriskiehl/Gooey 在它的帮助下我们可以非常方便的将一个命令行程序升级成一个图形 ...

  9. 傅立叶变换系列(五)快速傅立叶变换(FFT)

    说明: 傅里叶级数.傅里叶变换.离散傅里叶变换.短时傅里叶变换...这些理解和应用都非常难,网上的文章有两个极端:“Esay”  Or  “Boring”!如果单独看一两篇文章就弄懂傅里叶,那说明你真 ...

随机推荐

  1. 程序员之殇 —— (The Beginning of the End)噩梦、崩坏

    Look at all those faces out there (当我环视周遭的一张张脸孔) We are so different(我们是如此的不同) But we have one thing ...

  2. for循环去重排序

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. 配置国内PIP源方法

    python开发者都知道,当我们pip install安装扩展库的时候,经常遇到安装失败(超时)等,有时候是因为国外镜像被屏蔽了,带来不少麻烦, 随着国内python开发的增多,越来越多企业都开放了自 ...

  4. bat复制文件夹下所有文件到另一个目录

    一个需求,网上了半天都是错了,所以记一下吧,方便你我. copy是文件拷贝,文件夹拷贝需要用到xcopy @echo off::当前盘符set curPath=%cd%set digPath =&qu ...

  5. PHP $_SERVER['HTTP_REFERER'] 获取前一页面的 URL 地址

    转载:http://www.5idev.com/p-php_server_http_referer.shtml 使用 $_SERVER['HTTP_REFERER'] 将很容易得到链接到当前页面的前一 ...

  6. MyBatis之基于XML的动态SQL

    先说下我的梦想,大学的时候一直想着是能开店卖胡辣汤,到目前依然还是我的梦想,上周一家出版社联系我问我有没有时间可以合作出书,这也是我的梦想之一,想了想还是放弃了,至少觉得目前不行,毕竟工作还不到五年, ...

  7. Hive字段中文注释乱码解决办法

    Hive字段中文乱码,如执行 show create table xxx 时,表级别注释.字段级别注释发现有乱码现象, 一般都是由hive 元数据库的配置不当造成的. 此时可按如下步骤进行配置调整: ...

  8. [转]maven打包报错:Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.5:test

    源文URL:http://blog.csdn.net/caiwenfeng_for_23/article/details/44514947 mvn compile  没有问题,mvn package的 ...

  9. flannel 网络问题排查

    1. 如果你发现 k8s容器无法访问外网? 重启docker 原因是,docker重启后会重新生成网桥.网络不通的原因是flannel启动后生成的网络覆盖了docker的网络,当你重启docker后, ...

  10. python 操作python

    #!/usr/bin/env python#_*_ coding:utf-8 _*_ import MySQLdb # 打开门conn = MySQLdb.connect(host='192.168. ...