题目
题目描述
第二类斯特林数
{
n
m
}
\begin{Bmatrix} n \\m \end{Bmatrix}
{nm}表示把
n
n
n个不同元素划分成
m
m
m个相同的集合中(不能有空集)的方案数
给定
n
n
n,对于所有的整数
i
∈
[
0
,
n
]
i\in[0,n]
i∈[0,n],你要求出
{
n
i
}
\begin{Bmatrix} n \\i \end{Bmatrix}
{ni}
由于答案会非常大,所以你的输出需要对
167772161
167772161
167772161(
2
25
×
5
+
1
2^{25}\times 5+1
225×5+1,是一个质数)取模
输入格式
一行一个正整数 n n n,意义见题目描述
输出格式
共一行
n
+
1
n+1
n+1个非负整数
你需要按顺序输出
{
n
0
}
,
{
n
1
}
,
{
n
2
}
,
…
,
{
n
n
}
\begin{Bmatrix} n \\0 \end{Bmatrix},\begin{Bmatrix} n \\1 \end{Bmatrix},\begin{Bmatrix} n \\2 \end{Bmatrix},\dots,\begin{Bmatrix} n \\n \end{Bmatrix}
{n0},{n1},{n2},…,{nn}的值
样例
样例输入
3
样例输出
0 1 3 1
数据范围与提示
对于
20
%
20\%
20%的数据,
n
⩽
1000
n\leqslant 1000
n⩽1000
对于
100
%
100\%
100%数据,
1
⩽
n
⩽
2
×
1
0
5
1\leqslant n\leqslant 2\times 10^5
1⩽n⩽2×105
题解
不会斯特林数的戳我
{
n
m
}
=
1
m
!
∑
i
=
0
m
(
−
1
)
i
(
m
i
)
(
m
−
i
)
n
=
1
m
!
∑
i
=
0
m
(
−
1
)
i
m
!
i
!
(
m
−
i
)
!
(
m
−
i
)
n
=
∑
i
=
0
m
(
−
1
)
i
i
!
(
m
−
i
)
n
(
m
−
i
)
!
\begin{Bmatrix}n\\m\end{Bmatrix}=\frac{1}{m!}\sum \limits_{i=0}^m(-1)^i\binom{m}{i}(m-i)^n=\frac{1}{m!}\sum \limits_{i=0}^m(-1)^i\frac{m!}{i!(m-i)!}(m-i)^n=\sum \limits_{i=0}^m\frac{(-1)^i}{i!}\frac{(m-i)^n}{(m-i)!}
{nm}=m!1i=0∑m(−1)i(im)(m−i)n=m!1i=0∑m(−1)ii!(m−i)!m!(m−i)n=i=0∑mi!(−1)i(m−i)!(m−i)n
看,这是什么?是不是一个漂亮的卷积式?
还没看出来?设
f
(
x
)
=
∑
i
⩾
0
(
−
1
)
i
i
!
x
i
,
g
(
x
)
=
∑
i
⩾
0
i
n
i
!
x
i
f(x)=\sum \limits_{i\geqslant 0} \frac{(-1)^i}{i!}x^i,g(x)=\sum\limits_{i\geqslant 0}\frac{i^n}{i!}x^i
f(x)=i⩾0∑i!(−1)ixi,g(x)=i⩾0∑i!inxi,则
{
n
m
}
\begin{Bmatrix}n\\m\end{Bmatrix}
{nm}就是
f
(
x
)
f(x)
f(x)和
g
(
x
)
g(x)
g(x)的卷积
所以,我们就可以愉快地使用逆天塔(NTT)了!
附上代码:
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int mod=167772161,g=3;
int n,len=1,ln,r[800010],cj[800010],a[800010],b[800010];
int POW(int a,int b)
{
int ans=1;
for(;b;b>>=1){
if(b&1) ans=1ll*ans*a%mod;
a=1ll*a*a%mod;
}
return ans;
}
void NTT(int *a,int flag)
{
for(int i=0;i<len;i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int k=1;k<len;k<<=1) for (int i=0,w1=POW(g,(mod-1)/(k<<1));i<len;i+=(k<<1)) for(int j=0,w=1;j<k;j++,w=1ll*w*w1%mod){
int x=a[i+j],y=1ll*w*a[i+j+k]%mod;
a[i+j]=(x+y)%mod,a[i+j+k]=(x-y+mod)%mod;
}
if(flag==-1){
a[0]=1ll*a[0]*POW(len,mod-2)%mod;
for(int i=1,inv=POW(len,mod-2);i<=len/2;i++){
a[i]=1ll*a[i]*inv%mod;
if(i!=len-i) a[len-i]=1ll*a[len-i]*inv%mod;
swap(a[i],a[len-i]);
}
}
}
int main()
{
cin>>n,n++,cj[0]=cj[1]=1;
for(int i=2;i<n;i++) cj[i]=(mod-1ll*(mod/i)*cj[mod%i]%mod)%mod;
for(int i=1;i<n;i++) cj[i]=1ll*cj[i-1]*cj[i]%mod;
for(int i=0,f=1;i<n;f=mod-f,i++) a[i]=1ll*f*cj[i]%mod,b[i]=1ll*POW(i,n-1)*cj[i]%mod;
while(len<=(n<<1)) len<<=1,ln++;
for(int i=0;i<len;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(ln-1));
NTT(a,1),NTT(b,1);
for(int i=0;i<len;i++) a[i]=1ll*a[i]*b[i]%mod;
NTT(a,-1);
for(int i=0;i<n;i++) cout<<a[i]<<" ";
}