真的分治fft
以前学的分治fft f[i]=sigma(f[i-x]*g[x]),其中g[x]已知
那么我们可以用cdq分治来做(l,mid 对mid+1,t的影响)
而现在的$f[i]=sum(f(i-x)*f(x))$
我们如果沿用刚才的方法 会发现有$f(t-h)$这一项
而$t-h>mid$是有可能的
所以我们要在后续处理这件事情
先将$f[l,mid]*f[l,mid]$乘起来
如果$t-h<h$ 还要算$f[1,t-h]*f[h,mid]$ 注意还要乘2
注意多次用fft 每次还原a,b数组 因为那个n是要比m大的,所以只清空到m的0是有问题的
1e5的数据开O2要2s 预料之中了
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) struct cp{ double a,b; }; const int N=3e5+5; int n,m,l,r[N],f[N]; int a[N],b[N],w[N],G=3; const int mo=998244353; const int p=mo; IL int fsp(rint x,rint y) { rint ans=1; while (y) { if (y&1) ans=(1ll*ans*x)%mo; x=(1ll*x*x)%mo; y>>=1; } return ans; } void fft(int *a,int o) { for (int i=0;i<n;i++) if (i>r[i]) swap(a[i],a[r[i]]); for (rint i=1;i<n;i*=2) { rint wn=fsp(G,(p-1)/(i*2)); w[0]=1; rep(j,1,i-1) w[j]=(1ll*w[j-1]*wn)%p; for (rint j=0;j<n;j+=(i*2)) { rint *x=a+j,*y=a+i+j; for (rint k=0;k<i;k++) { const int t=(1ll*w[k]*y[k])%p; y[k]=x[k]-t; if (y[k]<0) y[k]+=p; if (y[k]>p) y[k]-=p; x[k]=x[k]+t; if (x[k]>p) x[k]-=p; } } } if (o==-1) { reverse(&a[1],&a[n]); for (int i=0,inv=fsp(n,p-2);i<n;i++) a[i]=1ll*a[i]*inv%p; } } void query() { l=0; for (n = 1; n <= m; n <<= 1) l++; for (int i=0;i<n;i++) r[i]=(r[i/2]/2)|((i&1)<<(l-1)); fft(a,1), fft(b,1); for (int i=0;i<n;i++) a[i]=1ll*a[i]*b[i]%p; fft(a,-1); } #define mid ((h+t)/2) IL void js(rint &x,rint y) { x+=y; x%=mo; } void cdq_fz(int h,int t) { if (h==t) return; cdq_fz(h,mid); if (t-h<h) { n=m=t-h+(mid-h+1); rep(i,1,t-h) a[i-1]=f[i]; rep(i,h,mid) b[i-h]=f[i]; query(); rep(i,mid+1,t) if (i-h-2>=0) js(f[i],(2*a[i-h-2])%mo); rep(i,0,n) a[i]=b[i]=0; } n=m=2*(mid-h+1); rep(i,h,mid) a[i-h]=b[i-h]=f[i]; query(); rep(i,mid+1,t) if (i-(2*h+1)>=0) js(f[i],a[i-(2*h+1)]); rep(i,0,n) a[i]=b[i]=0; cdq_fz(mid+1,t); } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); ios::sync_with_stdio(false); int k; cin>>k; f[1]=1; f[2]=1; cdq_fz(1,k); cout<<f[k]<<endl; return 0; }
对拍
#include <bits/stdc++.h> using namespace std; #define rep(i,h,t) for (int i=h;i<=t;i++) const int mo=998244353; int f[1100]; int main() { freopen("1.in","r",stdin); freopen("2.out","w",stdout); ios::sync_with_stdio(false); int n; cin>>n; f[1]=1; f[2]=1; rep(i,3,n) rep(k,1,i-2) f[i]+=(1ll*f[k]*f[i-k-1])%mo,f[i]%=mo; cout<<f[n]<<endl; return 0; }
还有说多项式右移
f=f*f>>1+g