博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[多项式算法](Part 5)分治FFT 学习笔记
阅读量:5109 次
发布时间:2019-06-13

本文共 2238 字,大约阅读时间需要 7 分钟。

其他多项式算法传送门:

分治FFT

分治FFT是一种基于CDQ分治(不是很懂和CDQ有什么关系)的算法,主要用于在\(O(nlog^2n)\)的时间复杂度内计算以下内容:

给定数列\(g_1\sim g_{n-1}\),求\(f_0\sim f_{n-1}\),其中\(f_i\)满足

\[ f_0=1\\ f_i=\sum_{j=1}^jf_{i-j}\times g_j \]

分析

我们可以借鉴分治的思想,对于当前的\(f_l\sim f_r\),设\(mid=\lfloor\frac{l+r}{2}\rfloor\)

先递归计算\(f_l\sim f_{mid}\),接着考虑前半部分对后面的贡献。

设对\(f_x(mid+1\le x\le r)\)的贡献为\(w_x\),则有

\[ w_x=\sum_{i=l}^{mid}f_i\times g_{x-i} \]
为了下面推导方便,把范围扩大,设\(f_i=0(mid+1\le i\le r)\)
\[ w_x=\sum_{i=l}^{x-1}f_i\times g_{x-i}\\ w_x=\sum_{i=0}^{x-l-1}f_{i+l}\times g_{x-i-l} \]
此时设\(a_i=f_{i+l},b_i=g_{i+1}\),则有:
\[ w_x=\sum_{i=0}^{x-l-1}a_i\times b_{x-l-1-i} \]
那么就会发现这是一个卷积的形式,使用FFT计算即可。

好像挺简单的?以前都没敢学来着

代码

例题:

这里我使用NTT来实现算法,当然使用FFT也是没有问题的。

加了IO优化,代码可能有点乱?

时间复杂度 \(O(nlog^2n)\)

空间复杂度 \(O(n)\)

// luogu-judger-enable-o2#include 
#include
#include
#include
#include
#define rint register inttypedef long long ll;//----- IO optimize -----#define Getchar (p1==p2&&(p2=(p1=In)+fread(In,1,1<<20,stdin),p1==p2)?EOF:*p1++)char In[1<<20],*p1=In,*p2=In,Ch,Out[1<<21],*Outp=Out,St[15],*Tp=St;inline int Getint(register int x=0){ while(!isdigit(Ch=Getchar)); for(;isdigit(Ch);Ch=Getchar)x=x*10+(Ch^48); return x;}inline void Putint(int x,char c){ do *Tp++=x%10^48;while(x/=10); do *Outp++=*--Tp;while(Tp!=St); *Outp++=c;}const int p=998244353,g1=3,g2=(p+1)/3;//g2为1/3 mod pinline int Add(int a,int b){return (a+=b)>=p?a-p:a;}inline ll Pow(ll a,ll b){ ll Res=1; for(;b;b>>=1,a=a*a%p) if(b&1)Res=Res*a%p; return Res%p;}namespace Poly{ int r[1<<18]; void NTT(int n,int* A,const int g)//没学过NTT?大丈夫,换成你喜欢的FFT即可 { for(rint i=0;i
>1]>>1)|((i&1)<<(l-1)); NTT(n,A,g1),NTT(n,B,g1); for(rint i=0;i
>1,Len=(r-l+1),n=1; CDQ_FFT(f,g,l,Mid); while(n<=Len)n<<=1; memset(A,0,n*sizeof(int)); memset(B,0,n*sizeof(int)); for(rint i=l;i<=Mid;++i)A[i-l]=f[i]; for(rint i=1;i<=r-l;++i)B[i-1]=g[i]; Multiply(n,A,B); for(rint i=Mid+1;i<=r;++i)f[i]=Add(f[i],A[i-l-1]); CDQ_FFT(f,g,Mid+1,r); }}int n,f[1<<18],g[1<<18];int main(){ n=Getint(),f[0]=1; for(rint i=1;i

分治FFT还是比较简单易懂的。

其中还有一个小优化:对于递归到范围较小的序列,直接暴力卷积,常数更小。

参考资料:

转载于:https://www.cnblogs.com/LanrTabe/p/11305470.html

你可能感兴趣的文章
white-space、word-break、word-wrap和text-overflow
查看>>
图论(网络流):SCOI 2007 修车
查看>>
python-装饰器&生成器&迭代器
查看>>
“因为数据库正在使用,所以无法获得对数据库的独占访问权。”处理
查看>>
控件缩放
查看>>
IOS问题汇总:2015-1-8 SBJson解析时报错—json文件字符非法
查看>>
c# int Int32 Int64 的区别
查看>>
[视频]K8飞刀 一键免杀 IE神洞网马教程
查看>>
正则表达式常用操作符
查看>>
Java环境变量的配置
查看>>
python基础 递归函数
查看>>
stm32 定时器与占空比
查看>>
C# CsvFile 类
查看>>
ECNU1328
查看>>
centos7 yum安装LAMP
查看>>
Logstash常用filter插件
查看>>
加减与有符号和无符号库
查看>>
关于FIR的modelsim
查看>>
Using Post-Form Trigger In Oracle Forms
查看>>
Redis 简介
查看>>