关于FFT(思路来源+板子整理)

思路来源

FFT详解

https://blog.csdn.net/ggn_2015/article/details/68922404

FFT代码

https://blog.csdn.net/hlyfalsy/article/details/9938547

https://blog.csdn.net/XieNaoban/article/details/69486299

FFT+NTT的理解

https://blog.csdn.net/qq_37136305/article/details/81184873

关于蝴蝶操作

https://blog.csdn.net/JuneWindy/article/details/79156335

关于IDFT矩阵的逆的证明

https://blog.csdn.net/f_zyj/article/details/76037583

FFT例题 3idiots

http://www.cnblogs.com/kuangbin/archive/2013/07/24/3210565.html

牛客十一赛例题 FFT+原根

https://blog.csdn.net/u013534123/article/details/82919834

感谢这么多答主,让我用了10h终于理解了FFT。

启发式FFT模板

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1<<18,mod=1e5+3;
double PI=acos(-1.0);
 
int n,a,q,k;
int c[N],s[N];
 
struct C{
	double r,i;
	C(){}
	C(double a,double b){r=a,i=b;}
	C operator + (C x){return C(r+x.r,i+x.i);}
	C operator - (C x){return C(r-x.r,i-x.i);}
	C operator * (C x){return C(r*x.r-i*x.i,r*x.i+i*x.r);}
}w[N],A[N],B[N];
int R[N];
vector <int> colors[N<<1];
struct cmp{
	bool operator ()(int a,int b){
		return colors[a].size()>colors[b].size();
	}
};
priority_queue <int,vector<int>,cmp> heap;
void FFT(C a[],int n){
	for (int i=0;i<n;i++)
		if (i<R[i])
			swap(a[i],a[R[i]]);
	for (int t=n>>1,d=1;d<n;d<<=1,t>>=1)
		for (int i=0;i<n;i+=(d<<1))
			for (int j=0;j<d;j++){
				C tmp=w[t*j]*a[i+j+d];
				a[i+j+d]=a[i+j]-tmp;
				a[i+j]=a[i+j]+tmp;
			}
}
void FFT_times(vector <int> &a,vector <int> &b,vector <int> &c){
	int n,d;
	for (int i=0;i<a.size();i++)
		A[i]=C(a[i],0);
	for (int i=0;i<b.size();i++)
		B[i]=C(b[i],0);
	for (n=1,d=0;n<a.size()+b.size()-1;n<<=1,d++);
	for (int i=0;i<n;i++){
		R[i]=(R[i>>1]>>1)|((i&1)<<(d-1));
		w[i]=C(cos(2*PI*i/n),sin(2*PI*i/n));
	}
	for (int i=a.size();i<n;i++)
		A[i]=C(0,0);
	for (int i=b.size();i<n;i++)
		B[i]=C(0,0);
	FFT(A,n),FFT(B,n);
	for (int i=0;i<n;i++)
		A[i]=A[i]*B[i],w[i].i*=-1.0;
	FFT(A,n);
	c.clear();
	for (int i=0;i<=a.size()+b.size()-2;i++)
		c.push_back(((LL)(A[i].r/n+0.5))%mod);
}
int modpow(int x,int n,int mod)
{
	int res=1;
	for(;n;n>>=1,x=1ll*x*x%mod)
	if(n&1)res=1ll*res*x%mod;
	return res;
}
int main(){
	scanf("%d%d%d",&n,&a,&q);
	for(int i=1;i<=n;++i)
	scanf("%d",&s[i]);
	while (!heap.empty())
		heap.pop();
	int sz=0;
	for (int i=1;i<=n;i++){
		colors[++sz].clear();
		colors[sz].push_back(modpow(a,s[i],mod));
		colors[sz].push_back(1);
		heap.push(sz);
	}
	while (heap.size()>=2){
		int x=heap.top();
		heap.pop();
		int y=heap.top();
		heap.pop();
		FFT_times(colors[x],colors[y],colors[++sz]);
		colors[x].clear(),colors[y].clear();
		heap.push(sz);
	}
	c[0]=1;//C(n,0)
	for(int i=1;i<=n;++i)
	c[i]=1ll*c[i-1]*(n-i+1)%mod*modpow(i,mod-2,mod)%mod;
	int inv=modpow(1-a+mod,mod-2,mod);
	for(int i=1;i<=q;++i)
	{
		scanf("%d",&k);
		int res=(c[k]-colors[sz][n-k]+mod)%mod;
		res=1ll*res*inv%mod;
		printf("%d\n",res);
	}
	return 0;
}

 

FFT快速傅里叶变换)是一种高效的算法,可以在O(nlogn)时间复杂度下计算离散傅里叶变换(DFT)。虽然使用vector实现FFT是比较常见的方法,但也可以使用数组实现FFT。 下面给出一个使用数组实现FFT的C++代码: ```cpp #include <bits/stdc++.h> using namespace std; const double PI = acos(-1); struct Complex { double real, imag; Complex() {} Complex(double r, double i): real(r), imag(i) {} inline Complex operator+(const Complex &c) const { return Complex(real + c.real, imag + c.imag); } inline Complex operator-(const Complex &c) const { return Complex(real - c.real, imag - c.imag); } inline Complex operator*(const Complex &c) const { return Complex(real * c.real - imag * c.imag, real * c.imag + imag * c.real); } }; void FFT(Complex *a, int n, int flag) { for (int i = 1, j = 0; i < n; i++) { for (int k = n; j ^= k >>= 1, ~j & k;); if (i < j) swap(a[i], a[j]); } for (int m = 2; m <= n; m <<= 1) { Complex wm(cos(2 * PI / m), flag * sin(2 * PI / m)); for (int k = 0; k < n; k += m) { Complex w(1, 0); for (int j = k; j < k + (m >> 1); j++, w = w * wm) { Complex u = a[j], t = w * a[j + (m >> 1)]; a[j] = u + t, a[j + (m >> 1)] = u - t; } } } if (flag == -1) for (int i = 0; i < n; i++) a[i].real /= n; } void Convolution(int *a, int na, int *b, int nb, int *res) { static Complex A[1 << 21], B[1 << 21]; int n = na + nb - 1, m = 1; while (m < n) m <<= 1; for (int i = 0; i < m; i++) { A[i] = i < na ? Complex(a[i], 0) : Complex(0, 0); B[i] = i < nb ? Complex(b[i], 0) : Complex(0, 0); } FFT(A, m, 1), FFT(B, m, 1); for (int i = 0; i < m; i++) A[i] = A[i] * B[i]; FFT(A, m, -1); for (int i = 0; i < n; i++) res[i] = (int)(A[i].real + 0.5); } int main() { int a[] = {1, 2, 3, 4}, b[] = {5, 6, 7}; int n = sizeof(a) / sizeof(int), m = sizeof(b) / sizeof(int); static int res[1 << 21]; Convolution(a, n, b, m, res); for (int i = 0; i < n + m - 1; i++) cout << res[i] << " "; return 0; } ``` 上述代码中,`FFT`函数实现了FFT的核心算法,`Convolution`函数实现了两个多项式的卷积。其中,`Complex`结构体表示复数,`FFT`函数的flag参数为1表示进行DFT,为-1表示进行IDFT。`Convolution`函数中使用`static`关键字定义了A和B数组,避免在函数栈上分配大量空间导致栈溢出。注意这里的n和m分别表示两个多项式的次数(不是系数个数),res数组的长度应该为n+m-1。 需要注意的是,这里的数组实现与vector实现类似,只是使用数组代替了vector,因此在实际应用中,可以根据自己的需要选择vector或数组来实现FFT
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Code92007

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值