把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【洛谷5395】第二类斯特林数·行

点此看题面

  • 给定\(n\),对于所有\(i=0\sim n\),求出\(S_2(n,i)\)
  • \(n\le2\times10^5\)

第二类斯特林数·行

关于第二类斯特林数的基础性质可见:斯特林数的基础性质与斯特林反演的初步入门

为求解一行第二类斯特林数,首先我们要知道它的组合表示

\[S_2(n,m)=\frac1{m!}\sum_{k=0}^m(-1)^k\times C(m,k)\times (m-k)^n \]

我们把组合数拆开,发现其中的\(m!\)与前面的\(\frac1{m!}\)恰好约掉,剩下的部分可以写成:

\[S_2(n,m)=\sum_{k=0}^m\frac{(-1)^k}{k!}\times\frac{(m-k)^n}{(m-k)!} \]

这可以看作一个卷积的形式,于是我们构造两个生成函数:

\[F(x)=\sum_{k=0}^{+\infty}\frac{(-1)^k}{k!}x^k\\ G(x)=\sum_{k=0}^{+\infty}\frac{k^n}{k!}x^k \]

二者相卷即可得到\(S_2(n)\)的生成函数了。

这应该算是快速求斯特林数的四类问题中最简单的一个了吧。

代码:\(O(nlogn)\)

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200000
#define X 167772161
using namespace std;
int n,S[N<<2],S2[N<<2];
I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
namespace Poly
{
	#define PR 3
	int P,L,A[N<<2],B[N<<2],R[N<<2];I void NTT(int* s,CI op)
	{
		RI i,j,k,x,y,U,S;for(i=0;i^P;++i) i<R[i]&&(swap(s[i],s[R[i]]),0);
		for(i=1;i^P;i<<=1) for(U=QP(QP(PR,op),(X-1)/(i<<1)),j=0;j^P;j+=i<<1) for(S=1,
			k=0;k^i;S=1LL*S*U%X,++k) s[j+k]=((x=s[j+k])+(y=1LL*S*s[i+j+k]%X))%X,s[i+j+k]=(x-y+X)%X;
	}
	I void Mul(CI n,int* a,int* b)
	{
		RI i;P=1,L=0;W(P<=2*n) P<<=1,++L;for(i=0;i^P;++i) A[i]=a[i],B[i]=b[i],R[i]=(R[i>>1]>>1)|((i&1)<<L-1);
		for(NTT(A,1),NTT(B,1),i=0;i^P;++i) A[i]=1LL*A[i]*B[i]%X;
		RI t=QP(P,X-2);for(NTT(A,X-2),i=0;i<=n;++i) a[i]=1LL*A[i]*t%X;
	}
}
int main()
{
	RI i,t=1;for(scanf("%d",&n),i=0;i<=n;++i) i&&(t=1LL*t*QP(i,X-2)%X),S2[i]=(i&1?X-1LL:1LL)*t%X,S[i]=1LL*QP(i,n)*t%X;//构造两个生成函数
	for(Poly::Mul(n,S2,S),i=0;i<=n;++i) printf("%d ",S2[i]);return 0;//直接卷起来即可
} 
posted @ 2021-06-03 12:37  TheLostWeak  阅读(124)  评论(0编辑  收藏  举报