多项式乘法
FFT主要用于快速求多项式的乘积。多项式的乘积就叫做卷积
对
多项式的性质:用任意
证明:设这个多项式
设
于是我们现在要解决的问题是如何快速将一个多项式的系数表示法(也就是我们通常写出来的多项式)与点表示法互相转换
下文的
系数表示法转点表示法:我们要在取
假设
设
1.
2.
3.
4.
现在,我们将
将
现在,设
也就是说我们要求出将
点表示法转换为系数表示法:设我们现在已经知道了
证明:
,最后一步成立是因为
于是我们设
最后讲一下实现。实践证明,如果用递归来实现的话,常数是非常大的,所以我们一般利用迭代来实现
假设现在
我们现在需要快速获得最后一行的顺序。观察,第一行的二进制位与最后一行对应的二进制位刚好为翻转关系。比如第一行的
证明:考虑一个数如何走到最后一层。从第一层到第二层,如果其末尾是
代码见下
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10;
const double PI=acos(-1);
int n,m,len;
complex<double> y[3][N<<2];
int rev[N<<2];
void change(int op)//交换
{
for(int i=0;i<len;i++)
if(i<rev[i]) swap(y[op][i],y[op][rev[i]]);//防止交换两次
}
void fft(int op,int on)//像BFS一样从下往上一层一层地合并
{
change(op);
for(int h=2;h<=len;h<<=1)//h为当前这一层的区间长度
{
complex<double> wn(cos(2*PI/h),sin(on*2*PI/h));//将单位圆分成h份
for(int j=0;j<len;j+=h)//合并起始点
{
complex<double> w(1,0);
for(int k=j;k<j+h/2;k++)
{
complex<double> u=y[op][k],t=w*y[op][k+h/2];
y[op][k]=u+t,y[op][k+h/2]=u-t;
//蝴蝶变换,见OI-wiki
w*=wn;
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n+1;i++)//千万注意这里要加一
{
int a;
scanf("%d",&a);
complex<double> u(a,0);//complex是C++自带的一个类
y[0][i-1]=u;
}
for(int i=1;i<=m+1;i++)
{
int a;
scanf("%d",&a);
complex<double> u(a,0);
y[1][i-1]=u;
}
len=n+m+1;
for(int i=0;;i++)//补齐
if(len==(1<<i)) break;
else if(len<(1<<i))
{
len=1<<i;
break;
}
for(int i=0;i<len;i++)//这一步操作见OI-wiki的位逆序置换O(n)实现
{
rev[i]=rev[i>>1]>>1;
if(i&1) rev[i]|=len>>1;
}
fft(0,1),fft(1,1);
for(int i=0;i<len;i++)
y[2][i]=y[0][i]*y[1][i];
fft(2,-1);
for(int i=0;i<=n+m;i++)
printf("%d ",(int)(real(y[2][i])/len+0.5));//这里都要这么写,不然有精度误差
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战