【题解】P5364 [SNOI2017]礼物

提供一个讨论区有人提出但没细讲的斯特林数做法,复杂度 \(O(k^2)\) 且可优化到 \(O(k \log k)\)

前置知识:第二类斯特林数的常用性质。

题目传送门

下文中为了方便设 \(m=n-1\)

首先发现题目让我们求 \(\sum_{i=1}^m 2^{m-i} \times i^k +n^k\),这个式子的推导别的题解都有写我就不写了。

为方便,考虑求 \(\sum_{i=0}^m 2^{m-i} \times i^k\)

可以发现它和常见的第二类斯特林数应用中的求自然数 \(k\) 次幂和很像,所以考虑用同样的方法做。

代入第二类斯特林数的性质式子 \(i^k=\sum_{j=0}^k{k \brace j}j!{i \choose j}\),推一波式子:

\[\begin{aligned} ans &=\sum_{i=0}^m 2^{m-i} \times i^k \\ &=\sum_{i=0}^m 2^{m-i} \sum_{j=0}^k{k \brace j}j!{i \choose j} \\ &=\sum_{j=0}^k {k \brace j}j! \sum_{i=0}^m 2^{m-i} {i \choose j} \\ &=\sum_{j=0}^k {k \brace j}j! \sum_{i=j}^m 2^{m-i} {i \choose j} \\ \end{aligned} \]

\(g(p)=\sum_{i=p}^m 2^{m-i} {i \choose p}\),这个式子怎么求呢?考虑递推搞出下一项:

\[\begin{aligned} g(p) &=\sum_{i=p}^m 2^{m-i} {i \choose p} \\ &=\sum_{i=p+1}^m 2^{m-i} {i \choose p}+2^{m-p}\\ &=\sum_{i=p+1}^m 2^{m-i} \times ({i+1 \choose p+1}-{i \choose p+1})+2^{m-p}\\ &=\sum_{i=p+1}^m 2^{m-i} \times {i+1 \choose p+1}-\sum_{i=p+1}^m 2^{m-i}{i \choose p+1}+2^{m-p}\\ &=\sum_{i=p+2}^{m+1} 2^{m-i+1} {i \choose p+1}-g(p+1) +2^{m-p}\\ &={m+1 \choose p+1}-g(p+1) +2\sum_{i=p+2}^{m} 2^{m-i} {i \choose p+1} +2 \times 2^{m-(p+1)}\\ &={m+1 \choose p+1}-g(p+1) +2\sum_{i=p+1}^{m} 2^{m-i} {i \choose p+1}\\ &={m+1 \choose p+1} +g(p+1) \end{aligned} \]

反过来,有 \(g(p)=g(p-1)-{m+1 \choose p} =g(p-1)-{n \choose p}\)

于是求出边界 \(g(0)=\sum_{i=0}^m 2^{m-i} {i \choose 0}=\sum_{i=0}^m 2^i=2^{m+1}-1=2^n-1\) 然后递推即可求出 \(g\)

所以只要枚举 \(j\),算出 \(\sum_{j=0}^k {k \brace j}j!g(j)\) 即可算出答案。

复杂度 \(O(k^2)\),瓶颈在于预处理第二类斯特林数,用 NTT 卷积求一行的第二类斯特林数可优化到 \(O(k \log k)\)

主要部分代码(马蜂较诡异,勿喷):

inline ll md(ll x){return x<0?x+mod:x;}
inline ll qpow(ll d,ll z){
	ll res=1ll;
	for(;z;z>>=1ll,d=d*d%mod) if(z&1ll) res=res*d%mod;
	return res;
}

signed main(){
	ll n=read();int k=read();
	inv[0]=inv[1]=stl[1][1]=1ll;
	for(re int i=2;i<=k;++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
	for(re int i=2;i<=k;++i) for(re int j=1;j<=i;++j) stl[i][j]=(stl[i-1][j-1]+j*stl[i-1][j])%mod;
	ll f=1ll,g=md(qpow(2ll,n)-1),c=1ll,ans=qpow(n%=mod,k);
	for(re int j=0;j<=k;++j,f=f*j%mod,g=md(g-(c=c*(n-j+1ll)%mod*inv[j]%mod))) ans=(ans+stl[k][j]*f%mod*g)%mod;
	printf("%lld\n",ans);
	return 0;
}
posted @ 2022-01-30 21:01  WhaleAtCola  阅读(87)  评论(1编辑  收藏  举报