【BZOJ4555】[Tjoi2016&Heoi2016]求和
Description
在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 Input
3
Sample Output
87
题解:读书少,没见过第二类斯特林数,于是去百度找了定义及通项公式。
将n个不同的球放入m个无差别的盒子中,要求盒子非空,有几种方案?
由定义可知,原题中的j<=i可以变成j<=n,所以开始推式子啦!
然后右面是什么?卷积!直接NTT完成任务。
不要忘记讨论等比数列公比为1的情况!
#include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const ll P=998244353; const ll G=3; const int maxn=(1<<19)+10; int n,len; ll ans; ll A[maxn],B[maxn],ine[maxn],jcc[maxn],jc[maxn]; ll pm(ll x,ll y,ll z) { ll ret=1; while(y) { if(y&1) ret=ret*x%P; x=x*x%P,y>>=1; } return ret; } void NTT(ll *a,int f) { int i,j,k,h; ll t; for(i=k=0;i<len;i++) { if(i>k) swap(a[i],a[k]); for(j=len>>1;(k^=j)<j;j>>=1); } for(h=2;h<=len;h<<=1) { ll wn=pm(G,f==1?(P-1)/h:P-1-(P-1)/h,P); for(j=0;j<len;j+=h) { ll w=1; for(k=j;k<j+h/2;k++) t=a[k+h/2]*w%P,a[k+h/2]=(a[k]-t+P)%P,a[k]=(a[k]+t)%P,w=w*wn%P; } } if(f==-1) { t=pm(len,P-2,P); for(i=0;i<len;i++) a[i]=a[i]*t%P; } } int main() { scanf("%d",&n); int i; for(len=1;len<=n+n;len<<=1); ine[1]=ine[0]=jcc[1]=jcc[0]=jc[1]=jc[0]=1; for(i=2;i<=n;i++) ine[i]=(P-(P/i)*ine[P%i])%P,jcc[i]=jcc[i-1]*ine[i]%P,jc[i]=jc[i-1]*i%P; for(i=0;i<=n;i++) { A[i]=(((i&1)?-1:1)*jcc[i]+P)%P; if(i==1) B[i]=(n+1)*jcc[i]%P; else B[i]=(1-pm(i,n+1,P)+P)*pm(1-i,P-2,P)%P*jcc[i]%P; } NTT(A,1),NTT(B,1); for(i=0;i<len;i++) A[i]=A[i]*B[i]%P; NTT(A,-1); for(i=0;i<=n;i++) ans=(ans+jc[i]*pm(2,i,P)%P*A[i]%P)%P; printf("%lld",ans); return 0; }