概念
多项式乘法时,我们发现暴力乘十分缓慢,但是点值乘十分快速。考虑求
一个
设多项式
对其奇偶分类得
提取
化简得
设
则
我们发现可以递归
但是时间复杂度不对
然后是一些高深件
复数
定义
则所有形如
复平面
类似坐标系,纵虚横实。复数
加法:与向量加法一样
乘法:复数相乘,模长相乘,幅角相加。
单位根
在复平面上,以原点为圆心,
单位根的幅角为周角的
欧拉公式有:
性质
性质
性质
图上自证不难
FFT
承接高深件
高能推柿子
带入
带入
不难发现,两式的值可以互相转换,且两室分别处理了一半区间。递归处理,复杂度
IFFT
函数转点并相乘后,需要转化回系数。此时使用傅里叶逆变换。
拉差
拉差不行,还是要推柿子。
设向量
推柿子懒了,多项式早日消失
最终
代码
递归实现即可
使用STL:complex实现复数
但是但是,递归常数很大。
改成迭代就可以了。
尻尻板子:
#include<iostream>
#include<cstdio>
#include<complex>
#include<cmath>
#include<algorithm>
using namespace std;
double pi=acos(-1);
int tax[5000001];
void Rev(int n)
{
int d=n>>1;
int len=-1;
tax[++len]=0;
tax[++len]=d;
for(int i=2;i<=n;i<<=1)
{
d>>=1;
for(int p=0;p<i;p++)
{
tax[++len]=tax[p]|d;
}
}
}
void FFT(complex<double> *A,int N)
{
for(int i=1;i<N;i++)
{
if(tax[i]>i)
{
swap(A[i],A[tax[i]]);
}
}
for(int len=2,M=1;len<=N;M=len,len<<=1)
{
complex<double> W(cos(pi/M),sin(pi/M));
complex<double> w(1.0,0.0);
for(int l=0,r=len-1;r<=N;l+=len,r+=len)
{
complex<double> w0=w;
for(int p=l;p<l+M;p++)
{
complex<double> x=A[p]+w0*A[p+M];
complex<double> y=A[p]-w0*A[p+M];
A[p]=x;
A[p+M]=y;
w0*=W;
}
}
}
}
void IFFT(complex<double> *A,int N)
{
FFT(A,N);
reverse(A+1,A+N);
}
int n,m;
complex<double> F[5000001],G[5000001];
int main()
{
scanf("%d%d",&n,&m);
for(int i=0,_;i<=n;i++)
{
scanf("%d",&_);
F[i]=_;
}
for(int i=0,_;i<=m;i++)
{
scanf("%d",&_);
G[i]=_;
}
int p2=1;
while(p2<=m+n) p2<<=1;
Rev(p2);
FFT(F,p2);
FFT(G,p2);
for(int i=0;i<p2;i++)
{
F[i]*=G[i];
}
IFFT(F,p2);
for(int i=0;i<=n+m;i++)
{
printf("%d ",int(F[i].real()/p2+0.5));
}
}
NTT板子
#include<iostream>
#include<cstdio>
#include<complex>
#include<cmath>
#include<algorithm>
#define int long long
#define mod 998244353
using namespace std;
double pi=acos(-1);
int tax[5000001];
int n,m;
void Rev(int pn)
{
for(int i=0;i<pn;i++)
{
tax[i]=tax[i>>1]>>1|((i&1)<<(max((int)ceil(log2(n+m)),1ll)-1));
}
}
long long poww(int a,int b)
{
int re=1;
while(b)
{
if(b&1)
{
re*=a;
re%=mod;
}
a*=a;
a%=mod;
b>>=1;
}
return re;
}
void NTT(long long *a,int n,int type) //type:1正0反
{
for(int i=0;i<n;++i)
{
if(i<tax[i])
{
swap(a[i],a[tax[i]]);
}
}
for(int i=1;i<n;i<<=1)
{
long long gn=poww(3,(mod-1)/(i<<1));
for(int j=0;j<n;j+=(i<<1))
{
long long g0=1;
for(int k=0;k<i;++k,g0=g0*gn%mod)
{
long long x=a[j+k],y=g0*a[i+j+k]%mod;
a[j+k]=(x+y)%mod;
a[i+j+k]=(x-y+mod)%mod;
}
}
}
if(type!=1)
{
int nn=poww(n,mod-2);
reverse(a+1,a+n);
for(int i=0;i<n;i++)
{
a[i]=1ll*a[i]*nn%mod;
}
}
}
long long F[5000001],G[5000001];
signed main()
{
scanf("%lld%lld",&n,&m);
for(int i=0,_;i<=n;i++)
{
scanf("%lld",&_);
F[i]=_;
}
for(int i=0,_;i<=m;i++)
{
scanf("%lld",&_);
G[i]=_;
}
int p2=1;
while(p2<=m+n) p2<<=1;
Rev(p2);
NTT(F,p2,1);
NTT(G,p2,1);
for(int i=0;i<p2;i++)
{
F[i]*=G[i];
}
NTT(F,p2,0);
for(int i=0;i<=n+m;i++)
{
printf("%lld ",F[i]);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现