当前位置: 首页 > news >正文

(笔记)多项式基础 FFT

多项式

\[F(x)=\sum_{i=0}^{i-1}a_ix^i \]

对多项式进行乘法,就是对两个多项式进行加法卷积。其中卷积结果 \(C(k)=\sum_{i=0}^kA(i)B(k-i)\)

分治乘法

\(A(x)\) 左右拆半,不足则末尾(最高位)补上 \(0\),令 \(n=2^k\)。则

\[A(x)=A_0(x)+x^{n/2}A_1(x) \]

\[A_0(x)=\sum_{i=0}^{n/2-1}a_ix^i,A_1(x)=\sum_{i=n/2}^na_ix^{i-n/2}=\sum_{i=0}^{n/2-1}a_{i+n/2}x^i \]

同理,\(B(x)\) 左右拆半,则卷积

\[\begin{aligned} AB&=(A_0+x^{n/2}A_1)(B_0+x^{n/2}B_1)\\ &=A_0B_0+x^nA_1B_1+x^{n/2}(A_0B_1+A_1B_0)\\ Q_1&=A_0B_0,Q2=A_1B_1,Q3=(A_0+A_1)(B_0+B_1)\\ AB&=Q_1+x^nQ_2+x^{n/2}(Q_3-Q_1-Q_2) \end{aligned} \]

这样可以转化为 \(3\) 个规模为 \(n/2\) 的子问题,总时间为 \(T(n)=O(n)+3T(n/2),T(n)=O(n^{\log_2 3})=O(n^{1.585})\)

点值与插值

点值:对于一个 \(x\)\(F(x)\) 的值。

插值:已知 \(F(x)\) 的若干点值,求其系数序列 \(G(x)\)

根据定义,\(F(x)=\sum_{i=0}^{n-1}x^iG(i)\)

(简记)拉格朗日插值

FFT 中的插值使用单位根反演实现。

复平面单位根

\(z=\cos\theta+i\sin\theta,\omega_n^k=\cos(\frac{2\pi k}{n})+i\sin(\frac{2\pi k}{n})\),其点集为单位圆均分成 \(n\) 份的点集,且点集包含 \(1\)

  • 性质 1\(\omega_n^k=\omega_n^{k+n}\)

  • 性质 2\(\omega_{nb}^{kb}=\omega_n^k\)

  • 性质 3:若 \(n\) 为偶数,\(\omega_n^{k+n/2}=-\omega_n^k\)

FFT

DFT

FFT 多项式乘法外层过程如下:

  • 选定 \(n(n=2^{k'})\) 个数 \(\omega_n,\omega_n^{2},...\omega_n^{n-1}\)
  • 对于 \(i\in [0,n-1]\) 求出点值 \(A(\omega_n^i),B(\omega_n^i)\)(DFT)
  • 根据 \(C(\omega_n^i)=A(\omega_n^i)B(\omega_n^i)\) 求出 \(C\) 的点值。
  • 插值求出 \(C(x)\) 的系数。(IDFT,即 DFT 逆过程)

类似分治乘法,我们采用拆半,但是是奇偶拆半。

\[\begin{aligned} F(x)&=FL(x^2)+xFR(x^2)\\ FL(x)&=\sum_{i\bmod 2=0,i\in[0,n-2]}a_ix^{i/2}\\ FR(x)&=\sum_{i\bmod 2=1,i\in[1,n-1 ]}a_ix^{(i-1)/2}\\ \end{aligned} \]

假设我们已经知道了一堆点值,代入 \(\omega_n^k,k\in[0,\frac{n}{2})\)

\[\begin{aligned} F(\omega_n^k)&=FL(\omega_n^{2k})+\omega_n^kFR(\omega_n^{2k})\\ &=FL(\omega_{n/2}^{k})+\omega_{n}^{k}FR(\omega_{n/2}^k) \end{aligned} \]

考虑到 \(FL,FR\) 的计算,我们每次实际分治时只需要计算所有 \(k<\frac{n}{2}\) 的部分,\(\frac{n}{2}\le k<n\) 的部分根据性质 1 \(\omega_{n/2}^{k+n/2}=\omega_{n/2}^k\),用到的 \(FL,FR\) 是和前面一样的,但是根据性质 3,我们在转移式子中用到的 \(\omega_n^{k+n/2}\) 需要变成 \(-\omega_n^k\),即:

\[F(\omega_n^{k+n/2})=FL(\omega_{n/2}^{k})-\omega_n^kFR(\omega_{n/2}^{k}) \]

这是 DFT 的部分。

IDFT

根据上面的 DFT:

\[F(k)=\sum_{i=0}^{n-1}(\omega_{n}^{k})^iG(i) \]

根据单位根反演:

\[n\times G(k)=\sum_{i=0}^{n-1}(\omega_{n}^{-k})^iF(i) \]

所以求出点值以后,我们再跑一边 DFT 即可。

这样我们就可以用子问题求出原问题的答案了,时间复杂度 \(T(n)=T(n/2)+O(n),T(n)=O(n\log n)\)

一些常数优化

迭代版神秘常数问题

  • 如果去掉分治过程直接迭代,先枚举起始点再枚举增量,否则会变得异常缓慢。

蝴蝶变换

  • 为了避免大规模数组拷贝,我们使用蝴蝶变换。注意到分治的过程中我们先不断地按照奇偶把数组切分然后分到两边,为了避免这个切分我们考虑一开始就把点放到它最下面那层分治所处的位置,然后合并和之前一样左边作为 \(FL\),右边作为 \(FR\)

    我们发现一个点 \(i\) 的二进制形式决定了其最终所处位置,把 \(i\) 视为 \(n=2^{k'}\)\(k'\) 位二进制数,那么 \(i\in[0,n-1]\),从上至下每次奇偶分类相当于看二进制最低位,\(0\) 就分到左边,\(1\) 就分到右边,然后右移一位。不妨把这个二进制数 reverse(翻转)一下,那么每次的选择及其权重和就恰好对应了翻转后的二进制数。于是预处理 \(i\)reverse \(tr[i]\),然后若 \(i<tr[i]\) 交换即可得到最下层位置(避免两次交换)。

三次变两次优化

构造出:

\[P(x)=F(x)+iG(x) \]

\[P(x)^2=F(x)^2-G(x)^2+2iF(x)G(x) \]

即把 \(F(x)\)\(iG(x)\) 系数相加得到 \(P(x)\) 系数后做一次 DFT,得到的点值平方后做 IDFT,最后得到的系数虚部 \(/2\) 就是 \(F(x)G(x)\)double 运算容易掉精度,承受能力为跨度上线 \(10^{12}\) 左右,如果相乘系数差太大(如一个 \(\in[10^{-6},10^{-5}]\),一个 \([10^5,10^6]\))在有平方项会导致 \(10^{24}\) 的精度跨度存在。解决办法就是乘上一个定值,做完 FFT 再除回去即可。

Code

分治版

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const double Pi=acos(-1);
const int N=1.35e6+5;
int n,m,tr[N<<1];
struct CP{CP(double xx=0,double yy=0){x=xx,y=yy;}double x,y;CP operator +(const CP &b)const{return (CP){x+b.x,y+b.y};}CP operator -(const CP &b)const{return (CP){x-b.x,y-b.y};}CP operator *(const CP &b)const{return (CP){x*b.x-y*b.y,x*b.y+y*b.x};}
}f[N<<1],g[N<<1];
void FFT(CP *f,int len,bool tf){if(len==1)return ;FFT(f,len/2,tf);FFT(f+len/2,len/2,tf);CP per(cos(2*Pi/len),sin(2*Pi/len)),now(1,0);if(!tf)per.y=-per.y;for(int k=0;k<len/2;k++){CP tt=now*f[k+len/2];f[k+len/2]=f[k]-tt;f[k]=f[k]+tt;now=now*per;}
}
int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=0;i<=n;i++)cin>>f[i].x;for(int i=0;i<=m;i++)cin>>g[i].x;m=m+n;for(n=1;n<=m;n<<=1);for(int i=0;i<n;i++)tr[i]=(tr[i>>1]>>1)|((i&1)?(n>>1):0);for(int i=0;i<n;i++)if(i<tr[i])swap(f[i],f[tr[i]]),swap(g[i],g[tr[i]]);FFT(f,n,1);FFT(g,n,1);for(int i=0;i<n;i++)f[i]=f[i]*g[i];for(int i=0;i<n;i++)if(i<tr[i])swap(f[i],f[tr[i]]);FFT(f,n,0);for(int i=0;i<=m;i++)cout<<(int)(f[i].x/n+0.49)<<' ';return 0;
}

迭代版

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const double Pi=acos(-1);
const int N=1.35e6+5;
int n,m,tr[N<<1];
struct CP{CP(double xx=0,double yy=0){x=xx,y=yy;}double x,y;CP operator +(const CP &b)const{return (CP){x+b.x,y+b.y};}CP operator -(const CP &b)const{return (CP){x-b.x,y-b.y};}CP operator *(const CP &b)const{return (CP){x*b.x-y*b.y,x*b.y+y*b.x};}
}f[N<<1],g[N<<1];
void FFT(CP *f,bool tf){if(n==1)return ;for(int i=0;i<n;i++)if(i<tr[i])swap(f[i],f[tr[i]]);for(int p=2;p<=n;p<<=1){int len=p>>1;CP per(cos(2*Pi/p),sin(2*Pi/p));if(!tf)per.y=-per.y;for(int l=0;l<n;l+=p){CP now(1,0);for(int k=l;k<l+len;k++){CP tt=now*f[k+len];f[k+len]=f[k]-tt;f[k]=f[k]+tt;now=now*per;}}}
}
int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=0;i<=n;i++)cin>>f[i].x;for(int i=0;i<=m;i++)cin>>g[i].x;m=m+n;for(n=1;n<=m;n<<=1);for(int i=0;i<n;i++)tr[i]=(tr[i>>1]>>1)|((i&1)?(n>>1):0);FFT(f,1);FFT(g,1);for(int i=0;i<n;i++)f[i]=f[i]*g[i];FFT(f,0);for(int i=0;i<=m;i++)cout<<(int)(f[i].x/n+0.49)<<' ';return 0;
}
http://www.rkmt.cn/news/3114.html

相关文章:

  • MySqlException: Incorrect string value: \xE6\x99\xBA\xE8\x83\xBD... for column FieldName at row 1
  • Burp Suite Professional 2025.9 发布 - Web 应用安全、测试和扫描
  • 征稿倒计时3天/武汉科技大学主办/医学人工智能/现可享优惠
  • 生成更智能,调试更轻松,SLS SQL Copilot 焕新登场!
  • NOI linux使用教程
  • springboot 文件处理框架
  • 将 seata 2.5 发布到私服
  • 一些感悟
  • 五款免费低代码平台深度横评:斑斑、简道云、宜搭、氚云、织信如何选?
  • 从需求出发:教你判断选斑斑还是织信
  • python如何在函数中使用全局变量?
  • C++ - STL - 键值对pair
  • 第四天学习:LSTM
  • MATLAB的稀疏自编码器实现
  • 题解:P2157 [SDOI2009] 学校食堂
  • vue3 与 element-plus
  • 第二周作业
  • 代码随想录算法训练营第一天| 704.二分查找、27.移除元素、977.有序数组的平方
  • 强制横屏 ios
  • 张量链式法则(下篇):揭秘Transpose、Summation等复杂算子反向传播,彻底掌握深度学习求导精髓!
  • 美客分销商城小程序系统介绍
  • C++ - STL - 静态数组array
  • C++ - STL - 集合set(元素具有排他性)
  • 批量删除所有 LXC 容器以及用户名
  • C++ - STL - 动态数组vector(矢量)
  • mt_12
  • 完整教程:【QT】-怎么实现瀑布图
  • 【初赛】二叉树性质和遍历 - Slayer
  • 详细解析苹果iOS应用上架到App Store的完整步骤与指南
  • 如何使用 OCR 提取扫描件 PDF 的文本(Python 实现) - E