随笔 - 22  文章 - 0 评论 - 0 阅读 - 536

概念

多项式乘法时,我们发现暴力乘十分缓慢,但是点值乘十分快速。考虑求 AB 的卷积。

一个 n 次多项式可以被 n+1 个点确定。

设多项式 A(x) 的系数为 (a0,a1,,an)

对其奇偶分类得 A(x)=a2ix2i+a2i+1x2i+1

提取 nA(x)=a2ix2i+xa2i+1x2i

化简得 A(x)=a2i(x2)i+xa2i+1(x2)i

(n21) 次多项式 A0=a2ix2i,A1=a2i+1x2i

A(x)=A0(x2)+xA1(x2)

我们发现可以递归

但是时间复杂度不对

然后是一些高深件

复数

定义 i2=1

则所有形如 z=a+bi 的数 z 组成的集合为复数集,记为 C。而 a 称为 z 的实部, b 为虚部。

复平面

类似坐标系,纵虚横实。复数 z 对应从原点指向 (a,b) 的向量。幅角为实轴横方向与向量的夹角,记为 θ

加法:与向量加法一样

乘法:复数相乘,模长相乘,幅角相加。(a+bi)(c+di)=(acbd)+(bc+ad)i

单位根

在复平面上,以原点为圆心,1 为半径作圆,所得的圆叫单位圆。以圆点为起点,圆的 n 等分点为终点,做 n 个向量,设幅角为正且最小的向量对应的复数为 ωn,称为 n 次单位根。剩余 n1 个点则为 ωn2,ωn3,ωn4,

单位根的幅角为周角的 1n

欧拉公式有:wnk=cosk2πn+isink2πn

性质 1: ωnk=ω2n2k

性质 2: ωnk+n2=ωnk

性质 3: wnn=1

图上自证不难

FFT

承接高深件

高能推柿子

A(x)=A0(x2)+xA1(x2)

带入 x=wnk(k<12n)

A(wnk)=A0(wn2k)+wnkA1(wn2k)

带入 x=wnk+n2(k<12n)

A(wnk+n2)=A0(wn2k+n)+wnk+n2A1(wn2k+n)

A(wnk)=A0(wn2k)+wnkA1(wn2k)

A(wnk)=A0(wn2k)wnkA1(wn2k)

不难发现,两式的值可以互相转换,且两室分别处理了一半区间。递归处理,复杂度 O(nlogn)

IFFT

函数转点并相乘后,需要转化回系数。此时使用傅里叶逆变换。

拉差

拉差不行,还是要推柿子。

设向量 c1,c2,cn1 满足 ck=j=1nyj(wnk)j

推柿子懒了,多项式早日消失

最终

ck=nak

ak=ckn

代码

递归实现即可

使用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]);
	}
}
posted on   lizhous  阅读(13)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示