apple365 的多项式合集!
重振卡门雄风,吾辈义不容辞!
目录:
- 快速傅里叶变换(FFT)
- NTT
正文
一,快速傅里叶变换(FFT)
前置芝士:
概念
- 时域:以时间为自变量,函数值为因变量的平面。
- 频域:以频率为自变量,振幅为因变量的坐标系。
- 多项式的系数表示法:
- 多项式的点值表示法:用
个点描述一个 次的多项式。
复数
复数=实部+虚部
对应的会有一个“复平面”。
用三角函数理解:
定义
引理:
- 消去引理:当
, , - 折半引理:若
且 ,则 个 次单位复数根的平方的集合就是 个 次复数根的集合。也就是说, - 求和引理:
,其中 , 不整除 , 。
对于 , 在 的值是
定义
假设
则
欧拉公式
拓展:
流程:
通过 FFT
通过点值乘法
通过 FFT 插值
标程
查看代码
#include<bits/stdc++.h>
//#define int long long
#define db double
using namespace std;
struct comp{
db a,b;
comp(){
}
comp(db _a,db _b){
a=_a,b=_b;
}
friend comp operator *(comp x,comp y){
return comp(x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a);
}
friend comp operator +(comp x,comp y){
return comp(x.a+y.a,x.b+y.b);
}
friend comp operator -(comp x,comp y){
return comp(x.a-y.a,x.b-y.b);
}
};
const int N=1000005;
comp I=comp(0.0,1.0);
const db pi=acos(-1.0);
int n,m;
comp a[N*3],b[N*3],tmp[N*3],ans[N*3];
void fft(comp* a,int len,int opt=1){
if(len==1)return;
comp* a0=new comp[len/2];
comp* a1=new comp[len/2];
for(int i=0;i<len;i+=2){
a0[i/2]=a[i];
a1[i/2]=a[i+1];
}
fft(a0,len>>1,opt);
fft(a1,len>>1,opt);
comp w_n=comp(cos(2*pi/len),opt*sin(2*pi/len));
comp w=comp(1,0);
for(int i=0;i<(len/2);++i){
a[i]=a0[i]+w*a1[i];
a[i+len/2]=a0[i]-w*a1[i];
w=w*w_n;
}
delete[]a0;
delete[]a1;
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=0;i<=n;++i)cin>>a[i].a;
for(int i=0;i<=m;++i)cin>>b[i].a;
int lim=1;
while(lim<=n+m)lim<<=1;
fft(a,lim);
fft(b,lim);
for(int i=0;i<=lim;++i)a[i]=a[i]*b[i];
fft(a,lim,-1);
for(int i=0;i<=n+m;++i)cout<<(int)(a[i].a/lim+0.5)<<' ';
return 0;
}
二.NTT
用原根代替一波单位根。
std:(分治 ver)
查看代码
#include<bits/stdc++.h>
#define int long long
#define swap(a,b) {auto c=a;a=b;b=c;}
using namespace std;
int rev[4000005];
const int N=1e6+5,mod=998244353,g=3,gi=332748118;
int n,m;
int qpow(int a,int b){
int ans=1,base=a;
while(b){
if(b&1)ans=ans*base%mod;
base=base*base%mod;
b>>=1;
}
return ans;
}
int a[N*3],b[N*3],c[N*3];
void NTT(int* A,int n,int flag=1){
for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
for(int mid=1;mid<n;mid<<=1) {
int wn=qpow(flag==1?g:gi,(mod-1)/(mid<<1));
for(int i=0;i<n;i+=(mid<<1)) {
int w=1;
for(int j=0;j<mid;++j,w=(w*wn)%mod){
int tmp0=A[i+j],tmp1=w*A[i+mid+j]%mod;
A[i+j]=(tmp0+tmp1)%mod;
A[i+mid+j]=(tmp0-tmp1)%mod;
}
}
}
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=0;i<=n;++i){
cin>>a[i];
a[i]=(a[i]%mod+mod)%mod;
}
for(int i=0;i<=m;++i)cin>>b[i];
int lim=1,L=0;
while(lim<=n+m)lim<<=1,++L;
for(int i=0;i<=lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
NTT(a,lim,1),NTT(b,lim,1);
for(int i=0;i<=lim;++i)a[i]=a[i]*b[i]%mod;
NTT(a,lim,-1);
for(int i=0;i<=n+m;++i)cout<<(a[i]*qpow(lim,mod-2)%mod+mod)%mod<<' ';
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现