LOJ#3300. 「联合省选 2020 A」组合数问题 第二类斯特林数
考场上忘了第二类斯特林数公式,过于智障,这里再重新推一遍.
首先,$S(i,j)$ 表示的意义是将 $i$ 个不同的球放入 $j$ 个相同的盒子中的方案数,且盒子不能为空.
那么有 $S(i,j)=S(i-1,j-1)+S(i-1,j) \times j$ 分别表示新开一个盒子/放入之前的盒子.
然后很多题会有 $\sum i^x$ 这种式子,这里 $i$ 的枚举范围很大,但是 $x$ 不大,所以用第二类斯特林数转化为 $O(x)$ 的做法
$\Rightarrow n^m=\sum_{i=0}^{min(n,m)} \binom{n}{i} i! S(m,i)$.
组合意义是 $n^m$ 表示将 $m$ 个不同的球放入 $n$ 个不同盒子的方案数,那么我们就枚举哪些盒子里装了球.
原题:求$\sum_{k=0}^{n} f(k) x^k \binom{n}{k}$.
其中 $f(x)$ 是一个 $m \leqslant 10^3$ 的多项式.
考虑枚举 $f(x)$ 中每一个系数的贡献,有 $\sum_{i=0}^{m} a_{i} \sum_{k=0}^{n} k^i x^k \binom{n}{k}$
这里 $k$ 很大,$i$ 很小,所以考虑将 $k^i$ 转化,得到
$\sum_{i=0}^{m} a_{i} \sum_{j=0}^{i} S(i,j) j! \sum_{k=j}^{n} \binom{k}{j} x^k \binom{n}{k}$
后面那个组合数可以拆出来一个 $\binom{n}{j}$ 然后用二项式定理逆战开就得到
$\sum_{i=0}^{m} a_{i} \sum_{j=0}^{i} S(i,j) n^{ \underline{j}}x^j (x+1)^{n-j}$.
提前预处理阶乘和下降幂,时间复杂度为 $O(m^2)$.
code:
#include <cstdio> #include <cstring> #include <algorithm> #define N 2004 #define ll long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; int n,x,mod,m; int a[N],S[N][N],lw[N],pw[N],xi[N]; int qpow(int xr,int y) { int tmp=1; for(;y;y>>=1,xr=(ll)xr*xr%mod) if(y&1) tmp=(ll)tmp*xr%mod; return tmp; } void init() { S[0][0]=1; for(int i=1;i<N;++i) { for(int j=1;j<=i;++j) { S[i][j]=(ll)(S[i-1][j-1]+(ll)S[i-1][j]*j%mod)%mod; } } } int main() { //setIO("input"); scanf("%d%d%d%d",&n,&x,&mod,&m); init(); for(int i=0;i<=m;++i) { scanf("%d",&a[i]); } pw[0]=lw[0]=1; for(int i=1;i<=m;++i) { lw[i]=(ll)lw[i-1]*(n-i+1)%mod; pw[i]=(ll)pw[i-1]*x%mod; xi[i]=(ll)qpow((x+1)%mod,n-i); } xi[0]=qpow((x+1)%mod,n); int ans=0; for(int i=0;i<=m;++i) { int tmp=0; for(int j=0;j<=i;++j) { (tmp+=(ll)S[i][j]*lw[j]%mod*pw[j]%mod*xi[j]%mod)%=mod; } (ans+=(ll)tmp*a[i]%mod)%=mod; } printf("%d\n",ans); return 0; }