真的分治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

posted @ 2018-09-01 15:22  尹吴潇  阅读(1359)  评论(0编辑  收藏  举报