洛谷p3803 FFT入门

洛谷p3803 FFT入门

浅谈FFT的基本原理:
对于两个多项式的卷积,可以O(n^2)求出来(妥妥的暴力)
显然一个多项式可以用 a 0 + a 1 X + a 2 X 2 + a 3 X 3 + a 4 X 4 a_0+a_1X+a_2X^2+a_3X^3+a_4X^4 a0+a1X+a2X2+a3X3+a4X4……表示。
也可以用(x1,y1),(x2,y2),(x3,y3),(x4,y4)的点集来表示。
用点值表示有一个好处:两个多项式的卷积可以直接取相同的x值,y值相乘得到。
那么,怎么转化为点值表示呢?
直接代进去?显然也是O(n^2),没用……
设 A ( X ) = a 0 + a 1 X + a 2 X 2 + a 3 X 3 + a 4 X 4 + a 5 X 5 . . A 0 ( X ) = a 0 + a 2 X + a 4 X 2 . . A 1 ( X ) = a 1 + a 3 X + a 5 X 2 . . 那 么 A ( X ) = A 0 ( X 2 ) + X ∗ A 1 ( X 2 ) \begin{aligned} 设A(X)&=a_0+a_1X+a_2X^2+a_3X^3+a_4X^4+a_5X^5..\\ A_0(X)&=a_0+a_2X+a_4X^2..\\ A_1(X)&=a_1+a_3X+a_5X^2..\\ \\ 那么A(X)&=A0(X^2)+X*A1(X^2) \end{aligned} A(X)A0(X)A1(X)A(X)=a0+a1X+a2X2+a3X3+a4X4+a5X5..=a0+a2X+a4X2..=a1+a3X+a5X2..=A0(X2)+XA1(X2)

然而, X 2 X^2 X2仍会有N种不同的取值。
引入一个复数根可以很好的解决这个问题:设 i = − 1 i=\sqrt{-1} i=1
e i θ = c o s θ + i ∗ s i n θ ( c o s θ + i ∗ s i n θ ) k = c o s k θ + i ∗ s i n k θ \boxed{e^{iθ}=cosθ+i∗sinθ\\ (cosθ+i∗sinθ)^k=coskθ+i*sinkθ} eiθ=cosθ+isinθ(cosθ+isinθ)k=coskθ+isinkθ

记 W n 1 = c o s 2 π n + i ∗ s i n 2 π n W n k = ( W n 1 ) k = c o s 2 π k n + i ∗ s i n 2 π k n 表 示 一 个 单 位 圆 分 成 n 份 中 的 第 k 份 ( k 次 方 ) ( W n k ) 2 = ( W n 1 ) 2 k = c o s 2 π ∗ 2 k n + i ∗ s i n 2 π ∗ 2 k n = c o s 2 π k n 2 + i ∗ s i n 2 π k n 2 = W n 2 k 那 么 A ( W n k ) = A 0 ( ( W n k ) 2 ) + W n k ∗ A 1 ( ( W n k ) 2 ) = A 0 ( W n 2 k ) + W n k ∗ A 1 ( W n 2 k ) \begin{aligned} 记W_n^1&=cos\frac{2π}{n}+i∗sin\frac{2π}{n}\\ W_n^k&=(W_n^1)^k=cos\frac{2πk}{n}+i∗sin\frac{2πk}{n}表示一个单位圆分成n份中的第k份(k次方)\\ (W_n^k)^2&=(W_n^1)^{2k}=cos\frac{2π*2k}{n}+i∗sin\frac{2π*2k}{n}=cos\frac{2πk}{\frac{n}{2}}+i∗sin\frac{2πk}{\frac{n}{2}}=W_\frac{n}{2}^k\\ \\ 那么A(W_n^k)&=A_0((W_n^k)^2)+W_n^k*A_1((W_n^k)^2)\\ &=A_0(W_\frac{n}{2}^k)+W_n^k*A_1(W_\frac{n}{2}^k) \end{aligned} Wn1Wnk(Wnk)2A(Wnk)=cosn2π+isinn2π=(Wn1)k=cosn2πk+isinn2πknk(k)=(Wn1)2k=cosn2π2k+isinn2π2k=cos2n2πk+isin2n2πk=W2nk=A0((Wnk)2)+WnkA1((Wnk)2)=A0(W2nk)+WnkA1(W2nk)

根据三角函数的周期性:2π为一个周期。
W n k = W n k   m o d   n W n n 2 = W 2 = c o s 2 π 2 + i ∗ s i n 2 π 2 = c o s π + i ∗ s i n π = − 1 W n t + n 2 = W n t W n n 2 = − W n t A ( W n k ) = A 0 ( W n 2 k ) + W n k ∗ A 1 ( W n 2 k ) 可 以 拆 成 两 部 分 , 设 t < n 2 A ( W n t ) = A 0 ( W n 2 t ) + W n t ∗ A 1 ( W n 2 t ) A ( W n t + n 2 ) = A 0 ( W n 2 t + n 2 ) + W n t + n 2 ∗ A 1 ( W n 2 t + n 2 ) = A 0 ( W n 2 t ) + W n t W n n 2 ∗ A 1 ( W n 2 t ) = A 0 ( W n 2 t ) − W n t ∗ A 1 ( W n 2 t ) \begin{aligned} W_n^k&=W_n^{k mod n}\\ W_n^\frac{n}{2}&=W_2=cos\frac{2π}{2}+i*sin\frac{2π}{2}=cosπ+i*sinπ=-1\\ W_n^{t+\frac{n}{2}}&=W_n^tW_n^\frac{n}{2}=-W_n^t\\ \\ A(W_n^k)&=A_0(W_\frac{n}{2}^k)+W_n^k*A_1(W_\frac{n}{2}^k)\\ 可以拆成两部分,设t&<\frac{n}{2}\\ A(W_n^t)&=A_0(W_\frac{n}{2}^t)+W_n^t*A_1(W_\frac{n}{2}^t)\\ A(W_n^{t+\frac{n}{2}})&=A_0(W_\frac{n}{2}^{t+\frac{n}{2}}) +W_n^{t+\frac{n}{2}}*A_1(W_\frac{n}{2}^{t+\frac{n}{2}})\\ &=A_0(W_\frac{n}{2}^t)+W_n^tW_n^\frac{n}{2}*A_1(W_\frac{n}{2}^t)\\ &=A_0(W_\frac{n}{2}^t)-W_n^t*A_1(W_\frac{n}{2}^t)\\ \end{aligned} WnkWn2nWnt+2nA(Wnk),tA(Wnt)A(Wnt+2n)=Wnk mod n=W2=cos22π+isin22π=cosπ+isinπ=1=WntWn2n=Wnt=A0(W2nk)+WnkA1(W2nk)<2n=A0(W2nt)+WntA1(W2nt)=A0(W2nt+2n)+Wnt+2nA1(W2nt+2n)=A0(W2nt)+WntWn2nA1(W2nt)=A0(W2nt)WntA1(W2nt)

A ( W n t ) 和 A ( W n t + n 2 ) 可 通 过 A 0 ( W n 2 t ) 和 W n t ∗ A 1 ( W n 2 t ) 推 导 得 到 A(W_n^t)和A(W_n^{t+\frac{n}{2}})可通过A_0(W_\frac{n}{2}^t)和W_n^t*A_1(W_\frac{n}{2}^t)推导得到 A(Wnt)A(Wnt+2n)A0(W2nt)WntA1(W2nt)

证毕,啦啦啦!

往下递归 W n 2 W_{\frac{n}{2}} W2n的答案。只需要 l o g 2 n log_2n log2n层,一直递归下去算就可以将时间优化到 O ( n l o g 2 n ) O(nlog_2n) O(nlog2n)

分治过程图解
在这里插入图片描述
非递归的蝴蝶变换

 上图摘自算法导论。算法导论下载,提取码qcfs

void FFT(Complex *A,int n,int DFT)
{
    for(int i=0;i<n;i++) if(i<rev[i]) swap(A[i],A[rev[i]]);
    for(int s=1;(1<<s)<=n;s++)
    {
        int mi=(1<<s);
        Complex wn=Complex(cos(2*pi/mi),sin(2*pi/mi)*DFT);
        for(int t=0;t<n;t+=mi)
        {
            Complex w=Complex(1,0);
            for(int j=0;j<(mi>>1);j++)
            {
                Complex u=A[t+j],v=w*A[t+j+(mi>>1)];
                A[t+j]=u+v; A[t+j+(mi>>1)]=u-v;
                w=w*wn;
            }
        }
    }
    if(DFT==-1) for(int i=0;i<n;i++) A[i].real/=n,A[i].image/=n;
}
for(int i=0;i<nn;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));

一题洛谷的裸题p3803
【代码】

#include<cstdio>
#include<algorithm>
#include<cmath>

using namespace std;

typedef long long ll;

const int N=1e6+10;
const double pi=acos(-1.0);
int n,m,nn,k;
struct Complex {
	double real,image;   //real+i*image
	Complex(){}
	Complex(double _real,double _image)
	{
		real=_real; image=_image;
	}
	friend Complex operator + (Complex A,Complex B) { return (Complex(A.real+B.real,A.image+B.image)); }
	friend Complex operator - (Complex A,Complex B) { return (Complex(A.real-B.real,A.image-B.image)); }
	friend Complex operator * (Complex A,Complex B) { return (Complex(A.real*B.real-A.image*B.image,A.real*B.image+A.image*B.real)); }
} A[N<<2],B[N<<2],C[N<<2];
int rev[N<<2];

void FFT(Complex *A,int n,int DFT)
{
	for(int i=0;i<n;i++) if(i<rev[i]) swap(A[i],A[rev[i]]);
	for(int s=1;(1<<s)<=n;s++)
	{
		int mi=(1<<s);
		Complex wn=Complex(cos(2*pi/mi),sin(2*pi/mi)*DFT);
		for(int t=0;t<n;t+=mi)
		{
			Complex w=Complex(1,0);
			for(int j=0;j<(mi>>1);j++)
			{
				Complex u=A[t+j],v=w*A[t+j+(mi>>1)];
				A[t+j]=u+v; A[t+j+(mi>>1)]=u-v;
				w=w*wn;
			}
		}
	}
	if(DFT==-1) for(int i=0;i<n;i++) A[i].real/=n,A[i].image/=n;
}

int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<=n;i++) { int xx; scanf("%d",&xx); A[i]=Complex(xx,0); }
	for(int i=0;i<=m;i++) { int xx; scanf("%d",&xx); B[i]=Complex(xx,0); }
	m+=n; k=0;
	for(nn=1;nn<=m;nn<<=1) k++;
	for(int i=0;i<nn;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
	FFT(A,nn,1); FFT(B,nn,1);
	for(int i=0;i<=nn;i++) C[i]=A[i]*B[i];
	FFT(C,nn,-1);
	for(int i=0;i<=m;i++) printf("%d ",(int)(C[i].real+0.5));
	printf("\n");
	return 0;
}

ps:这篇总结写得真心累……

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值