洛谷4721 【模板】分治 FFT

本文介绍了一种使用分治NTT(快速傅里叶变换)处理多项式卷积的方法,通过cdq分治思想,在递归过程中计算[l,mid]区间对[mid+1,r]区间的贡献,实现高效多项式乘法运算。代码示例展示了如何初始化、执行NTT变换及逆变换,并应用到具体问题中。

传送门

久违的多项式全家桶= =+

分治NTT 用的就是cdq分治的思想 对于当前递归到的区间[l,r] 我们处理出[l,mid]对[mid+1,r]答案的贡献

然后分治递归求解就可以啦qwq

这个贡献是前一半卷积的答案加过去就可以啦

对于x的贡献w_x = \sum_{i=l}^{mid} f_i*g_{x-i}

附代码。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cmath>
#define ll long long
#define mdn 998244353
#define G 3
#define mxn 200010
using namespace std;

int ksm(int bs,int mi)
{
	int ans=1;
	while(mi)
	{
		if(mi&1)	ans=(ll)ans*bs%mdn;
		bs=(ll)bs*bs%mdn; mi>>=1;
	}
	return ans;
}
int rev[mxn],inv;
int init(int n)
{
	int lim=1,l=0;
	while(lim<n)	lim<<=1,l++;
	for(int i=1;i<lim;i++)
		rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));
	inv=ksm(lim,mdn-2);
	return lim;
}

void NTT(int *a,int n,int f)
{
	for(int i=0;i<n;i++)	if(rev[i]>i)	swap(a[rev[i]],a[i]);
	for(int k=2;k<=n;k<<=1)
	{
		int Wn=ksm(G,(mdn-1)/k),mid=k>>1;
		if(f)	Wn=ksm(Wn,mdn-2);
		for(int w=1,i=0;i<n;i+=k,w=1)
		for(int j=0;j<mid;j++,w=(ll)w*Wn%mdn)
		{
			int x=a[i+j],y=(ll)w*a[i+mid+j]%mdn;
			a[i+j]=(x+y)%mdn;
			a[i+mid+j]=(x-y+mdn)%mdn;
		}
	}
	if(f)	for(int i=0;i<n;i++)	a[i]=(ll)a[i]*inv%mdn;
}

int f[mxn],g[mxn],h[mxn],a[mxn],b[mxn];
void cdq(int l,int r)
{
	if(l==r)	return;
	int mid=(l+r)>>1;
	cdq(l,mid); int lim = init(r-l+1);
	for(int i=0;i<=mid-l;i++)	a[i]=f[l+i];
	for(int i=mid-l+1;i<=lim;i++)	a[i]=0;
	for(int i=0;i<=r-l;i++)	b[i]=g[i];
	for(int i=r-l+1;i<=lim;i++)	b[i]=0;
	NTT(a,lim,0); NTT(b,lim,0);
	for(int i=0;i<lim;i++)	a[i]=(ll)a[i]*b[i]%mdn;
	NTT(a,lim,1);
	//for(int i=0;i<lim;i++)	printf("%d ",a[i]);
	for(int i=mid+1;i<=r;i++)	f[i]=(ll)(f[i]+a[i-l])%mdn;
	cdq(mid+1,r);
}
int n;
int main()
{
	scanf("%d",&n);
	for(int i=1;i<n;i++)	scanf("%d",&g[i]);
	f[0]=1;
	cdq(0,n);
	for(int i=0;i<n;i++)	printf("%d ",f[i]);
	return 0;
}

 

### 洛谷 FFT 题目与解法 洛谷平台上的 FFT(快速傅里叶变换)相关题目通常涉及多项式乘法、卷积计算以及字符串匹配等场景。以下是关于 FFT 的一些常见题型及解法的总结[^1]。 #### 1. 多项式乘法 FFT 最常见的应用之一是加速多项式的乘法运算。给定两个多项式 $A(x)$ 和 $B(x)$,直接相乘的时间复杂度为 $O(n^2)$,而使用 FFT 可以将时间复杂度优化到 $O(n \log n)$。以下是一个基于 FFT 的多项式乘法代码示例[^2]: ```cpp #include <iostream> #include <complex> #include <vector> using namespace std; typedef complex<double> cp; void FFT(vector<cp> &a, int n, int inv) { for(int i=0, j=0; i<n; ++i){ if(i > j) swap(a[i], a[j]); for(int k = n >> 1; (j ^= k) < k; k >>= 1); } for(int len=2; len<=n; len<<=1){ double ang = inv * 2 * acos(-1) / len; cp wlen(cos(ang), sin(ang)); for(int i=0; i<n; i+=len){ cp w(1, 0); for(int j=0; j<len/2; ++j){ cp u = a[i+j], v = a[i+j+len/2] * w; a[i+j] = u + v; a[i+j+len/2] = u - v; w *= wlen; } } } if(inv == -1){ for(auto &x : a) x /= n; } } vector<double> multiply(const vector<double> &a, const vector<double> &b){ int n = 1; while(n < (int)a.size() + (int)b.size()) n <<= 1; vector<cp> fa(a.begin(), a.end()), fb(b.begin(), b.end()); fa.resize(n); fb.resize(n); FFT(fa, n, 1); FFT(fb, n, 1); for(int i=0; i<n; ++i) fa[i] *= fb[i]; FFT(fa, n, -1); vector<double> res(n); for(int i=0; i<n; ++i) res[i] = fa[i].real(); return res; } ``` #### 2. 字符串匹配 FFT 还可以用于字符串匹配问题,例如通过将字符串转化为数值序列后进行卷积计算。以下是字符串匹配的一个简单实现[^2]: ```cpp #include <bits/stdc++.h> using namespace std; typedef complex<double> cp; const double PI = acos(-1); void fft(vector<cp> &a, bool inv){ int n = a.size(); for(int i=1,j=0;i<n-1;i++){ for(int k=n>>1;k>(j^=k);k>>=1); if(i<j) swap(a[i],a[j]); } for(int len=2;len<=n;len<<=1){ double ang = 2*PI/len*(inv?-1:1); cp wlen(cos(ang),sin(ang)); for(int i=0;i<n;i+=len){ cp w(1,0); for(int j=0;j<len/2;j++){ cp u = a[i+j], v = a[i+j+len/2]*w; a[i+j] = u+v; a[i+j+len/2] = u-v; w *= wlen; } } } if(inv){ for(auto &x:a) x/=n; } } int main(){ string s1,s2; cin >> s1 >> s2; int m = s1.size(), n = s2.size(); vector<cp> A(m), B(n); for(int i=0;i<m;i++) A[i] = s1[i]-'a'+1; for(int i=0;i<n;i++) B[i] = s2[i]-'a'+1; reverse(A.begin(), A.end()); int len = 1; while(len < m + n) len <<= 1; A.resize(len, 0); B.resize(len, 0); fft(A, false); fft(B, false); for(int i=0;i<len;i++) A[i] *= B[i]; fft(A, true); for(int i=m-1;i<n;i++) cout << fixed << setprecision(0) << A[i].real() << " "; } ``` #### 3. 洛谷 FFT 教程 洛谷平台上有一些高质量的 FFT 教程,例如《浅谈 FFT——从 DFT 到 FFT》[^1]。这篇教程详细介绍了 FFT 的数学原理、DFT 的定义以及如何用 FFT 加速多项式乘法。此外,还提供了丰富的代码示例和实际应用场景。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值