FFT入门
这篇文章会讲讲FFT的原理和代码。
先贴picks博客(又名FFT从入门到精通):http://picks.logdown.com/posts/177631-fast-fourier-transform
首先FFT是干嘛用的?
额其实在oi中它就是一个用来算“快速卷积”的东西。
卷积是啥?
给定两个数组a、b,求数组c使得:
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(i+j<n) c[i+j]+=a[i]*b[j];
这就叫做长度为n的“卷积”。
正常模拟是O(n^2)的,这时候我们就可以用FFT来加速到O(nlogn)!
我们发现,如果我们令a[i]为x^i的系数,那么a、b就可以表示为一个多项式,c就可以被表示为这两个多项式的乘积。
首先我们可以发现,我们对于一个n次多项式,可以用一个多项式的形式来表示它,也可以找到n个位置的值,这样也可以唯一确定这个多项式。
所以我们就初步有了一个思路,我们找到a、b在n个点处的取值,乘在一起,搞回去确定c的多项式形式。
为了和谐,我们一般令n为2的次幂。(注意)
关于这个东西一般有两种写法,一般被称为复数FFT和NTT。
先讲NTT好了......
假设a、b都是整系数多项式,然后模数P十分刺激,满足P是质数,$2^k|P-1$且$2^k>n$时,我们就可以使用NTT。
然后你还要知道原根的有关概念...简单来说就是原根的次幂在模P意义下循环节为$\varphi(P)$,对于素数来说就是P-1。
这里就说一点,998244353的原根是3...
设g为P的原根,那么我们令$\omega_n=g^{\frac{P-1}{n}}$,可以发现:
$\omega_{2n}^{2m}=\omega_{n}^m$,$\omega_{2n}^m=-\omega_{2n}^{m+n}$。(确实挺显然的)
那么我们取$\omega_n^k$,其中k∈{0...n-1},作为n个点,如何算出这n个点处的取值呢?
我们假设偶次项提出来作为a0,奇次项提出来作为a1。
(例如1+2x+3x^2+4x^3,偶次项提出来为1+3x,奇次项提出来为2+4x,注意这里的次数也要相应改变)
那么我们可以发现
所以我们可以用a0和a1的点值表示算出a的点值表示。
T(n)=2T(n/2)+O(n),由主定理复杂度为O(nlogn)。
接下来转回去的话,由于某种奇怪的性质(详细证明可以看picks博客),我们只要用$\omega_{n}^{-m}$代替原来的$\omega_n^{m}$,带进去,最后除以n就行了。即把那一堆$\omega$翻转一下。
当然如果你真这样瞎搞常数似乎真的挺大的,事实上有一些更靠谱的做法,上图:

开始我们把输入的数二进制位翻转,就可以得到左边,然后按这个图上进行蝶形运算(就是刚才那两个公式)就可以算出结果了。
额复数FFT更加简单。
我们令$\omega_{n}$为单位根,即满足$x^n=1$的复数,它可以看做复平面上x轴正方向绕逆时针方向旋转$\frac{2\pi}{n}$的复数。所以$\omega_n=cos(\frac{2\pi}{n})+sin(\frac{2\pi}{n})i$。
听起来十分靠谱...但是这种东西毕竟自己瞎写的话常数实在太大了...
下面这个是n+e的NTT模板,有改动,uoj34:
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
using namespace std;
#define ll long long
ll MOD=998244353;
ll w[2][666666];
ll qp(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=ans*a%MOD;
a=a*a%MOD; b>>=1;
}
return ans;
}
int K;
void fftinit(int n)
{
for(K=1;K<n;K<<=1);
w[0][0]=w[0][K]=1;
ll g=qp(3,(MOD-1)/K); //3是原根
for(int i=1;i<K;i++) w[0][i]=w[0][i-1]*g%MOD;
for(int i=0;i<=K;i++) w[1][i]=w[0][K-i];
}
void fft(int* x,int v)
{
for(int i=0,j=0;i<K;i++)
{
if(i>j) swap(x[i],x[j]);
for(int l=K>>1;(j^=l)<l;l>>=1);
}
for(int i=2;i<=K;i<<=1)
{
for(int j=0;j<K;j+=i)
{
for(int l=0;l<i>>1;l++)
{
ll t=(ll)x[j+l+(i>>1)]*w[v][K/i*l]%MOD;
x[j+l+(i>>1)]=(x[j+l]-t+MOD)%MOD;
x[j+l]=(x[j+l]+t)%MOD;
}
}
}
if(!v) return;
ll rv=qp(K,MOD-2);
for(int i=0;i<K;i++) x[i]=x[i]*rv%MOD;
}
int N,M,a[666666],b[666666],c[666666];
int main()
{
scanf("%d%d",&N,&M);
++N; ++M; int t=N+M-1;
for(int i=0;i<N;i++) scanf("%d",a+i);
for(int i=0;i<M;i++) scanf("%d",b+i);
fftinit(t); fft(a,0); fft(b,0);
for(int i=0;i<K;i++) c[i]=(ll)a[i]*b[i]%MOD;
fft(c,1);
for(int i=0;i<t;i++) printf("%d ",c[i]);
}
FFT入门的更多相关文章
- TOT 傅立叶变换 FFT 入门
HDU 1402,计算很大的两个数相乘. FFT 只要78ms,这里: 一些FFT 入门资料:http://wenku.baidu.com/view/8bfb0bd476a20029bd642d85. ...
- 洛谷p3803 FFT入门
洛谷p3803 FFT入门 ps:花了我一天的时间弄懂fft的原理,感觉fft的折半很神奇! 大致谈一谈FFT的基本原理: 对于两个多项式的卷积,可以O(n^2)求出来(妥妥的暴力) 显然一个多项式可 ...
- hdu1402 FFT入门
参考这里:http://www.cnblogs.com/pdev/p/4354705.html http://www.cnblogs.com/pdev/p/4354629.html 题意:求大数乘法 ...
- FFT 入门
推荐博客 :https://oi.men.ci/fft-notes/ 卷积的理解 : https://www.zhihu.com/question/22298352?rf=21686447 题目链接 ...
- bzoj2179: FFT快速傅立叶
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> ...
- 多项式FFT相关模板
自己码了一个模板...有点辛苦...常数十分大,小心使用 #include <iostream> #include <stdio.h> #include <math.h& ...
- 3-idiots hdu4609 母函数+FFT 组合数学题
http://acm.hdu.edu.cn/showproblem.php?pid=4609 题意:1e5个数,求取三个数能形成三角形的概率. 题解(这怎么会是fft入门题QAQ): 概率的算法就是三 ...
- 模板:快速傅里叶变换(FFT)
参考:http://blog.csdn.net/f_zyj/article/details/76037583 如果公式炸了请去我的csdn博客:http://blog.csdn.net/luyouqi ...
- HDU 1402 大数乘法 FFT、NTT
A * B Problem Plus Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
随机推荐
- iOS之 HTTP、Socket、TCP的区别(易混
一.HTTP 是一种超文本传输协议,全名hypertext transfer protocol,从字面意思上可以看出该协议用于规定客户端与服务端之间的传输规则, 传输的内容不限于文本(任意类型的数据) ...
- react学习笔记1
# 1.hello world 学习一个语言,最好的方式,我们需要去官网去查看文档(https://facebook.github.io/react),通过JSFiddle,便可以看到最简单的demo ...
- Asp.net MVC验证哪些事(2)-- 验证规则总结以及使用
上篇文章Asp.net MVC验证那些事(1)-- 介绍和验证规则使用中,介绍了Asp.net MVC中的验证功能以及如何使用.这里将对MVC中内置的验证规则进行总结. 一,查找所有验证规则 上篇文章 ...
- 微信网站设置右上角发送、分享的内容——.net版本
一.首先了解本文要解决的问题: 公司前一段开发了移动网站,老板喜欢通过微信看,然后把看到的东西通过右上角的按钮分享出来,但老板发现分享出来的东西,没有指定的图片,没有描述:所以我就得老老实实干活了.. ...
- MySQL数据库的导入和导出
1.导入数据库 在命令行下输入: mysql -u username -p test < /home/data/test.sql 说明: username 是 ...
- Oracle索引梳理系列(三)- Oracle索引种类之反向索引
版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...
- java -jar 执行 eclipse export 的 jar 包报错处理
1. 错误1:打 jar 包执行,报错,找不到 类库的 jar 包 F:\>java -jar remoteLogin.jarException in thread "AWT-Even ...
- SQL Server调优系列基础篇(并行运算总结篇二)
前言 上一篇文章我们介绍了查看查询计划的并行运行方式. 本篇我们接着分析SQL Server的并行运算. 闲言少叙,直接进入本篇的正题. 技术准备 同前几篇一样,基于SQL Server2008R2版 ...
- 烂泥:使用nginx利用虚拟主机搭建WordPress博客
本文由秀依林枫提供友情赞助,首发于烂泥行天下. 最近开始打算学习nginx web服务器,既然是学习还是以实用为目的的.我们在此以搭建WordPress博客为例. 搭建WordPress博客,我们需要 ...
- net-snmp添加自定义MIB
我所知道的添加自定义MIB的方法有三种 1.静态加载,将生成的.c和.h文件加入到相应的位置,重新编译snmp库,优点是不需要修改配置文件,缺点是每次添加都得重新编译: 2.动态加载,将生成的.c ...