题目大意
在2016年,佳媛姐姐刚刚学习了第二类斯特林数,非常开心。
现在他想计算这样一个函数的值:
$S(i,j)$表示第二类斯特林数,递推公式为:$S(i,j)=j\cdot S(i-1,j)+S(i-1,j-1),1\le j\le i-1$。
边界条件为:$S(i, i) = 1(0 \leq i), \ S(i, 0) = 0(1 \leq i)$
你能帮帮她吗?
题目分析
这是一道很屌的题。
这里讲第一种解法,第二种解法请看下一篇。
首先,使用${n \brace i}$表示斯特林数,组合意义为将$n$个不同元素划分到$i$个不带标号的非空集合的方案数。
不带标号意味着不能记重,我们可以先计算带标号的方案数${n \brace i}’$,在除以$i!$得到${n \brace i}$。
使用容斥原理推导:
${n \brace i}’=$包含$\ge0$个空集合方案数$-\ge1$个空集合方案数(记重)$+\ge2$个空集合方案数(记重)$-\cdots$
也就是:
式子的意思是先选出$k$个空集合,再将$n$个元素任意分配到其他集合中,不保证分配后无空集合。
然后代入答案式计算:
出现了,指数型生成函数!
设$a(x)=\sum_i(-1)^i\frac{x^i}{i!},b(x)=\sum_i(\sum\limits_{j=0}^ni^j)\frac{x^i}{i!}$。
为了方便转移,令$a[0]=b[0]=1$。
直接NTT即可。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| #include<bits/stdc++.h>
using namespace std;
typedef long long LL;
inline int Get_Int() { int num=0,bj=1; char x=getchar(); while(!isdigit(x)) {if(x=='-')bj=-1;x=getchar();} while(isdigit(x)) {num=num*10+x-'0';x=getchar();} return num*bj; }
const int maxn=262144+5; const LL mod=998244353,g=3;
LL Quick_Pow(LL a,LL b) { LL sum=1; for(; b; b>>=1,a=a*a%mod)if(b&1)sum=sum*a%mod; return sum; }
LL inv(LL x) {return Quick_Pow(x,mod-2);}
struct NumberTheoreticTransform { int n,rev[maxn]; LL omega[maxn],iomega[maxn]; void init(int n) { this->n=n; int x=Quick_Pow(g,(mod-1)/n); omega[0]=iomega[0]=1; for(int i=1; i<n; i++)omega[i]=omega[i-1]*x%mod,iomega[i]=inv(omega[i]); int k=log2(n); for(int i=0; i<n; i++) { int t=0; for(int j=0; j<k; j++)if(i&(1<<j))t|=1<<(k-j-1); rev[i]=t; } } void transform(LL *a,LL *omega) { for(int i=0; i<n; i++)if(i<rev[i])swap(a[i],a[rev[i]]); for(int len=2; len<=n; len*=2) { int mid=len>>1; for(LL *p=a; p!=a+n; p+=len) for(int i=0; i<mid; i++) { LL t=omega[n/len*i]*p[mid+i]%mod; p[mid+i]=(p[i]-t+mod)%mod; p[i]=(p[i]+t)%mod; } } } void dft(LL *a) {transform(a,omega);} void idft(LL *a) { transform(a,iomega); LL x=inv(n); for(int i=0; i<n; i++)a[i]=a[i]*x%mod; } } ntt;
int n; LL a[maxn],b[maxn],fac[maxn],invf[maxn];
int main() { n=Get_Int(); int T=1; while(T<=n)T<<=1; fac[0]=1; for(int i=1; i<=T; i++)fac[i]=fac[i-1]*i%mod; invf[T]=inv(fac[T]); for(int i=T; i>=1; i--)invf[i-1]=invf[i]*i%mod; a[0]=b[0]=1,b[1]=n+1; for(int i=1; i<=n; i++) { a[i]=((i&1?-1:1)*invf[i]+mod)%mod; if(i>1)b[i]=inv(i-1)*(Quick_Pow(i,n+1)-1)%mod*invf[i]%mod; } T<<=1; ntt.init(T); ntt.dft(a),ntt.dft(b); for(int i=0; i<T; i++)a[i]=a[i]*b[i]%mod; ntt.idft(a); LL ans=0; for(int i=0; i<=n; i++)ans=(ans+Quick_Pow(2,i)*fac[i]%mod*a[i]%mod)%mod; printf("%lld\n",ans); return 0; }
|