2017 3 11 分治FFT

  

考试一道题的递推式为$$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]$的转移预处理了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #define ll long long
 6 #define N 400005
 7 using namespace std;
 8 int n,k;
 9 const int p = 998244353;
10 ll poow[N],jie[N],ni[N];
11 ll pw(ll x,ll y)
12 {
13     ll lst=1;
14     while(y)
15     {
16         if(y&1)lst=lst*x%p;
17         x=x*x%p;
18         y>>=1;
19     }
20     return lst;
21 }
22 ll f[N];
23 int R[N],a[N],b[N];
24 void NTT(int *a,int n,int f,int L)
25 {
26     for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
27     for(int i=0;i<n;i++)if(i<R[i])swap(a[i],a[R[i]]);
28     for(int i=1;i<n;i<<=1)
29     {
30         int wn=pw(3,((p-1)/(i<<1)*f+p-1)%(p-1));
31         for(int j=0;j<n;j+=(i<<1))
32         {
33             int w=1;
34             for(int k=0;k<i;k++,w=1LL*w*wn%p)
35             {
36                 int x=a[j+k],y=1LL*a[j+k+i]*w%p;
37                 a[j+k]=(x+y)%p;a[j+k+i]=(x-y+p)%p;
38             }
39         }
40     }
41     if(f==-1)
42     {
43         int nw=pw(n,p-2);
44         for(int i=0;i<n;i++)a[i]=1LL*a[i]*nw%p;
45     }
46     return ;
47 }
48 void solve(int l,int r)
49 {
50     if(l==r)
51     {
52         f[l]=f[l]*jie[l-1]%p;
53         return ;
54     }
55     int mid=(l+r)>>1;
56     solve(l,mid);int len=r-l+1;int m=len<<1;
57     for(int i=1;i<len;i++)a[i]=poow[i];
58     for(int i=l;i<=mid;i++)b[i-l]=f[i]*ni[i]%p;
59     int L=0;for(len=1;len<m;len<<=1)L++;
60     for(int i=mid-l+1;i<len;i++)b[i]=0;
61     NTT(a,len,1,L);NTT(b,len,1,L);
62     for(int i=0;i<len;i++)a[i]=1LL*a[i]*b[i]%p;
63     NTT(a,len,-1,L);
64     for(int i=mid+1;i<=r;i++)f[i]=(f[i]+a[i-l])%p;
65     solve(mid+1,r);
66 }
67 int main()
68 {
69     scanf("%d%d",&n,&k);
70     jie[0]=1;ni[0]=1;
71     for(int i=1;i<=n;i++)jie[i]=(jie[i-1]*i)%p;
72     for(int i=1;i<=n;i++)ni[i]=pw(jie[i],p-2);
73     poow[0]=1;
74     for(int i=1;i<=n;i++)poow[i]=pw(i,k);
75     for(int i=1;i<=n;i++)f[i]=poow[i];
76     solve(1,n);
77     printf("%lld\n",f[n]);
78     return 0;
79 }

 

posted @ 2017-03-13 19:53  SD_le  阅读(236)  评论(0编辑  收藏  举报
重置按钮