【CF932E】Team Work(第二类斯特林数简单题)
- 求\(\sum_{i=1}^nC_n^i\times i^k\)。
- \(n\le10^9,k\le5\times10^3\)
我这种数学渣渣都能推出来的题目。
而且数据范围很友好,并不需要任何多项式优化。
自然数幂的转化
算是一个经典套路了。
考虑第二类斯特林数的性质:
\[i^k=\sum_{j=0}^{\min\{n,k\}}S_2(k,j)\times i^{\underline{j}}
\]
把它代入原式:
\[\sum_{i=1}^{n}C_n^i\times \sum_{j=0}^{\min\{n,k\}}S_2(k,j)\times i^{\underline{j}}
\]
看看数据范围,\(n\le10^9\)巨大无比,而\(k\le5\times10^3\)就非常好,所以我们提前\(j\)的枚举:
\[\sum_{j=0}^{\min\{n,k\}}S_2(k,j)\times \sum_{i=1}^n C_n^i\times i^{\underline{j}}
\]
针对后一个\(\sum\)中的式子,我们暴拆组合数和下降幂得到:
\[\sum_{i=1}^n \frac{n!}{i!(n-i)!}\times \frac{i!}{(i-j)!}=n!\sum_{i=1}^n\frac1{(n-i)!(i-j)!}
\]
后面这一项看起来莫名其妙,但实际上可以发现\((n-i)+(i-j)\)的和是定值\(n-j\)。
所以我们给它强行添上一个\((n-j)!\),也刚好让式子前面的\(n!\)变成一个可做的下降幂形式:
\[n^{\underline{j}}\sum_{i=1}^nC_{n-j}^{n-i}
\]
组合数上面的\(n-i\)就很难看,不妨用\(n-i\)去替换原本的\(i\)得到:
\[n^{\underline{j}}\sum_{i=0}^{n-1}C_{n-j}^i
\]
显然\(n-j\le n-1\),且\(i>n-j\)的时候\(C_{n-j}^i=0\)无用,所以原式等同于:
\[n^{\underline{j}}\sum_{i=0}^{n-j}C_{n-j}^i=n^{\underline{j}}\times 2^{n-j}
\]
代回原式:
\[\sum_{j=0}^{\min\{n,k\}}S_2(k,j)\times n^{\underline{j}}\times 2^{n-j}
\]
于是只要\(O(k^2)\)预处理第二类斯特林数就结束了。
代码:\(O(k^2)\)
#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 K 5000
#define X 1000000007
using namespace std;
int n,k,S2[K+5][K+5],dw[K+5];
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;}
int main()
{
RI i,j,m,t=0;scanf("%d%d",&n,&k),m=min(n,k);
for(S2[0][0]=i=1;i<=k;++i) for(j=1;j<=i;++j) S2[i][j]=(1LL*S2[i-1][j]*j+S2[i-1][j-1])%X;//预处理第二类斯特林数
for(dw[0]=i=1;i<=m;++i) dw[i]=1LL*dw[i-1]*(n-i+1)%X;//预处理下降幂
RI p=QP(2,n-m);for(i=m;i;p=2LL*p%X,--i) t=(1LL*S2[k][i]*dw[i]%X*p+t)%X;//同时维护好2的幂
return printf("%d\n",t),0;
}
待到再迷茫时回头望,所有脚印会发出光芒