Discription
在2016年,佳媛姐姐刚刚学习了第二类斯特林数,非常开心。
现在他想计算这样一个函数的值:
S(i, j)表示第二类斯特林数,递推公式为:
S(i, j) = j ? S(i ? 1, j) + S(i ? 1, j ? 1), 1 <= j <= i ? 1。
边界条件为:S(i, i) = 1(0 <= i), S(i, 0) = 0(1 <= i)
你能帮帮他吗?
Input
输入只有一个正整数
Output输出f(n)。
由于结果会很大,输出f(n)对998244353(7 × 17 × 223 + 1)取模的结果即可。
1 ≤ n ≤ 100000
Sample Input3
Sample Output
87
我们知道第二类斯特林数和排列数(下降幂)组合在一起可以表示n^k,又因为排列等于组合乘上一个阶乘,于是我们就可以开开心心的二项式反演,得到一个某一行(其实也可以很多行,鉴于这个式子的特殊性质,我们可以把不同行的同一列合并)某一列的斯特林数的表达式。
具体的说,S(k,n) = Σ (i^k / i!) * ((-1)^(n-i) / (n-i)!) [具体推导就不写了,就是一个二项式反演]。
这个式子的特殊性质太多了,首先它是一个卷积的形式,所以我们可以直接用NTT 在 N log N 的时间求出某一行的所有第二类斯特林数分别是多少;
并且只有 i^k 项和行数有关,所以同一列很好合并,于是这个题就做完了2333。
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=330005; const int ha=998244353; const int root=3,inv=ha/3+1; int a[maxn],b[maxn],jc[maxn]; int r[maxn],N,M,n,INV,l; inline int add(int x,int y){ x+=y; return x>=ha?x-ha:x; } inline int ksm(int x,int y){ int an=1; for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha; return an; } inline void NTT(int *c,const int f){ for(int i=0;i<N;i++) if(i<r[i]) swap(c[i],c[r[i]]); for(int i=1;i<N;i<<=1){ int omega=ksm(f==1?root:inv,(ha-1)/(i<<1)); for(int p=i<<1,j=0;j<N;j+=p){ int now=1; for(int k=0;k<i;k++,now=now*(ll)omega%ha){ int x=c[j+k],y=c[j+k+i]*(ll)now%ha; c[j+k]=add(x,y); c[j+k+i]=add(x,ha-y); } } } if(f==-1) for(int i=0;i<N;i++) c[i]=c[i]*(ll)INV%ha; } inline void init(){ jc[0]=1; for(int i=1;i<=n;i++) jc[i]=jc[i-1]*(ll)i%ha; for(int i=0;i<=n;i++){ if(!i) a[i]=1; else if(i==1) a[i]=n+1; else a[i]=add(ksm(i,n+1),ha-1)*(ll)ksm(add(i,ha-1)*(ll)jc[i]%ha,ha-2)%ha; if(i&1) b[i]=ha-ksm(jc[i],ha-2); else b[i]=ksm(jc[i],ha-2); } M=n<<1; for(N=1;N<=M;N<<=1) l++; for(int i=0;i<N;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1)); } inline void solve(){ NTT(a,1),NTT(b,1); for(int i=0;i<N;i++) a[i]=a[i]*(ll)b[i]%ha; INV=ksm(N,ha-2),NTT(a,-1); } inline void output(){ int ans=0,base=1; for(int i=0;i<=n;i++,base=add(base,base)) ans=add(ans,a[i]*(ll)base%ha*(ll)jc[i]%ha); printf("%d\n",ans); } int main(){ scanf("%d",&n); init(); solve(); output(); return 0; }