【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;
}