您的位置:首页 > 其它

2017 3 11 分治FFT

2017-03-13 19:53 344 查看
  

考试一道题的递推式为$$f[i]=\sum_{j=1}^{i} j^k \times (i-1)! \times \frac{f[i-j]}{(i-j)!}$$
这显然是一个卷积的形式,但$f$需要由自己卷过来(我也不知到怎么说),以前只会生成函数的做法,但这题好像做不了(谁教教我怎么做),于是无奈的写了一发暴力,看题解发现是分治FFT.
分治每层用$f[l]-f[mid]$与$a[1]-a[r-l]$做NTT。
这样显然每个$f[l]-f[mid]$对$f[mid+1]-f[r]$的贡献都考虑到了。
因为分治是从1开始的,所以$f[0]$的转移预处理了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define N 400005
using namespace std;
int n,k;
const int p = 998244353;
ll poow
,jie
,ni
;
ll pw(ll x,ll y)
{
ll lst=1;
while(y)
{
if(y&1)lst=lst*x%p;
x=x*x%p;
y>>=1;
}
return lst;
}
ll f
;
int R
,a
,b
;
void NTT(int *a,int n,int f,int L)
{
for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
for(int i=0;i<n;i++)if(i<R[i])swap(a[i],a[R[i]]);
for(int i=1;i<n;i<<=1)
{
int wn=pw(3,((p-1)/(i<<1)*f+p-1)%(p-1));
for(int j=0;j<n;j+=(i<<1))
{
int w=1;
for(int k=0;k<i;k++,w=1LL*w*wn%p)
{
int x=a[j+k],y=1LL*a[j+k+i]*w%p;
a[j+k]=(x+y)%p;a[j+k+i]=(x-y+p)%p;
}
}
}
if(f==-1)
{
int nw=pw(n,p-2);
for(int i=0;i<n;i++)a[i]=1LL*a[i]*nw%p;
}
return ;
}
void solve(int l,int r)
{
if(l==r)
{
f[l]=f[l]*jie[l-1]%p;
return ;
}
int mid=(l+r)>>1;
solve(l,mid);int len=r-l+1;int m=len<<1;
for(int i=1;i<len;i++)a[i]=poow[i];
for(int i=l;i<=mid;i++)b[i-l]=f[i]*ni[i]%p;
int L=0;for(len=1;len<m;len<<=1)L++;
for(int i=mid-l+1;i<len;i++)b[i]=0;
NTT(a,len,1,L);NTT(b,len,1,L);
for(int i=0;i<len;i++)a[i]=1LL*a[i]*b[i]%p;
NTT(a,len,-1,L);
for(int i=mid+1;i<=r;i++)f[i]=(f[i]+a[i-l])%p;
solve(mid+1,r);
}
int main()
{
scanf("%d%d",&n,&k);
jie[0]=1;ni[0]=1;
for(int i=1;i<=n;i++)jie[i]=(jie[i-1]*i)%p;
for(int i=1;i<=n;i++)ni[i]=pw(jie[i],p-2);
poow[0]=1;
for(int i=1;i<=n;i++)poow[i]=pw(i,k);
for(int i=1;i<=n;i++)f[i]=poow[i];
solve(1,n);
printf("%lld\n",f
);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: