- 求(sum_{i=1}^nC_n^i imes i^k)。
- (nle10^9,kle5 imes10^3)
我这种数学渣渣都能推出来的题目。
而且数据范围很友好,并不需要任何多项式优化。
自然数幂的转化
算是一个经典套路了。
考虑第二类斯特林数的性质:
[i^k=sum_{j=0}^{min{n,k}}S_2(k,j) imes i^{underline{j}}
]
把它代入原式:
[sum_{i=1}^{n}C_n^i imes sum_{j=0}^{min{n,k}}S_2(k,j) imes i^{underline{j}}
]
看看数据范围,(nle10^9)巨大无比,而(kle5 imes10^3)就非常好,所以我们提前(j)的枚举:
[sum_{j=0}^{min{n,k}}S_2(k,j) imes sum_{i=1}^n C_n^i imes i^{underline{j}}
]
针对后一个(sum)中的式子,我们暴拆组合数和下降幂得到:
[sum_{i=1}^n frac{n!}{i!(n-i)!} imes frac{i!}{(i-j)!}=n!sum_{i=1}^nfrac1{(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-jle 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}} imes 2^{n-j}
]
代回原式:
[sum_{j=0}^{min{n,k}}S_2(k,j) imes n^{underline{j}} imes 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
",t),0;
}