任意模长DFT

离散傅里叶变换(DFT)

首先引入DFT式:
V ( j ) = ∑ i = 0 n − 1 a i ω n i j V(j)=\sum_{i=0}^{n-1} a_i \omega_n^{ij} V(j)=i=0n1aiωnij
其中, a i a_i ai 为一长度为 n n n 的多项式 A ( x ) A(x) A(x) 的各项系数,即 A ( x ) = ∑ i = 0 n − 1 a i x i A(x)=\sum_{i=0}^{n-1}a_i x^i A(x)=i=0n1aixi n n n 也是DFT的模长。 V ( x ) V(x) V(x) 为多项式经过DFT后的多项式。 ω n \omega_n ωn n n n 次单位根,即 ω n = cos ⁡ ( 2 π n ) + i sin ⁡ ( 2 π n ) \omega_n = \cos(\frac{2 \pi}{n}) + i \sin(\frac{2 \pi}{n}) ωn=cos(n2π)+isin(n2π) i i i 为虚数单位,即 i 2 = − 1 i^2=-1 i2=1。此过程可以看做一个向量与范德蒙矩阵相乘。
类似的还有IDFT式:
V ( j ) = 1 n ∑ i = 0 n − 1 a i ω n − i j V(j)=\frac{1}{n} \sum_{i=0}^{n-1} a_i \omega_n^{-ij} V(j)=n1i=0n1aiωnij
根据定义,可以用时间复杂度为 O ( n 2 ) O(n^2) O(n2) 的算法解决。
log ⁡ 2 n ∈ Z \log_2n \in \Z log2nZ 时,可以用FFT解决该问题。时间复杂度 O ( n log ⁡ 2 n ) O(n \log_2n) O(nlog2n),空间复杂度 O ( n ) O(n) O(n)

#include<stdio.h>
#include<cmath>
#define R register int
#define D double
#define I inline
#define N 131072
#define PIE 3.141592653589793
struct Complex{
   
	D Real,Image;
	I void Read(){
   
		int x;
		scanf("%d",&x);
		Real=x;
	}
};
I Complex Pair(D A,D B){
   
	Complex res;
	res.Real=A;
	res.Image=B;
	return res;
}
I Complex operator+(Complex A,Complex B){
   
	return Pair(A.Real+B.Real,A.Image+B.Image);
}
I Complex operator-(Complex&A,Complex&B){
   
	return Pair(A.Real-B.Real,A.Image-B.Image);
}
I Complex operator*(Complex A,Complex B){
   
	return Pair(A.Real*B.Real-A.Image*B.Image,A.Image*B.Real+A.Real*B.Image);
}
I void Swap(Complex&A,Complex&B){
   
	Complex Tem;
	Tem=A;
	A=B;
	B=Tem;
}
I void FFT(Complex*A,const int len,const short type){
   
	int tem=0;
	for(R i=0;i!=len;i++){
   
		if(i<tem){
   
			Swap(A[i],A[tem]);
		}
		R j=len;
		do{
   
			j>>=1;
			tem^=j;
		}while(tem<j);
	}
	static Complex w[N];
	w[0]=Pair(1,0);
	for(R i=1;i!=len;i<<=1){
   
		Complex omg;
		omg=Pair(cos(PIE/i),sin(PIE/i)*type);
		for(R j=i-2>>1;j!=-1;j--){
   
			w[j<<1]=w[j];
			w[j<<1|1]=w[j]*omg;
		}
		for(R j=0;j!=len;j+=i<<1){
   
			for(R k=j;k!=i+j;k++){
   
				Complex T1=A[k],T2=A[i+k]*w[k-j];
				A[k]=T1+T2;
				A[i+k]=T1-T2;
			}
		}
	}
	if(type==-1){
   
		D t=1.0/len;
		for(R i=0;i!=len;i++){
   
			A[i].Real*=t;
			A[i].Image*=t;
		}
	}
}
int main(){
   
	return 0;
}

log ⁡ 2 n ∉ Z \log_2n \notin \Z log2n/Z 时,FFT不再适用。以下有两种解决方法:

1. 卷积

根据计数原理,有 i j = ( i + j 2 ) − ( i 2 ) − ( j 2 ) ij=\binom{i+j}{2}-\binom{i}{2}-\binom{j}{2} ij=(2i+j)(2i)(2j),带回DFT式,则有:
ω n ( j 2 ) V ( j ) = ∑ i = 0 n − 1 a i ω n − ( i 2 ) ω n ( i + j 2 ) \omega_n^{\binom{j}{2}}V(j)=\sum_{i=0}^{n-1} a_i \omega_n^{-\binom{i}{2}} \omega_n^{\binom{i+j}{2}} ωn(2j)V(j)=i=0n1aiωn(2i)ωn(2i+j)
因此利用FFT减法卷积即可。求解IDFT时同理。
时间复杂度 O ( n log ⁡ 2 n ) O(n \log_2n) O(nlog2n),空间复杂度 O ( n ) O(n) O(n)
若将 i j ij ij 拆为 − ( i − j ) 2 − i 2 − j 2 2 -\frac{(i-j)^2-i^2-j^2}{2} 2(ij)2i2j2 也可以卷积,但存在指数为分数,非常麻烦,甚至有时不存在或无意义。

2. 分治

d d d n n n 的最小非 1 1 1约数,设 m = n d , j = p d + q m=\frac{n}{d},j=pd+q m=dn,j=pd+q,其中 0 ⩽ p < m , 0 ⩽ q < d 0 \leqslant p<m,0 \leqslant q<d 0p<m,0q<d。带入DFT式,有:
V ( p d + q ) = ∑ i = 0 n − 1 a i ω n i ( p d + q ) V(pd+q)=\sum_{i=0}^{n-1}a_i \omega_n^{i(pd+q)} V(pd+q)=i=0n1aiωni(pd+q)
将括号展开,由于 ω m d d = ω m \omega_{md}^d=\omega_m ωmdd=ωm,所以:
V ( p d + q ) = ∑ i = 0 n − 1 a i ω m i p ω n i q V(pd+q)=\sum_{i=0}^{n-1}a_i \omega_m^{ip} \omega_n^{iq} V(pd+q)=i=0n1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值