CF 932E Team Work

原题题面

题目大意:求\(\sum\limits_{i=0}^{n}C_{n}^{i}i^{k}\)

我们根据套路\(n^{k}=\sum\limits_{i=0}^{k}C_{n}^{i}i!S_2(k,i)\)\(S_2\)表示第二类斯特林数。

\[原式=\displaystyle\sum_{i=0}^{n}C_{n}^{i}\sum_{j=0}^{k}C_{i}^{j}\cdot j!S_2(k,j)\\ =\sum_{i=0}^{n}C_n^i\sum_{j=0}^k C_i^jj!S_2(k,j) \]

因为\(k\)的规模远小于\(n\)的规模,所以我们交换一下求和符号,在最外层枚举到\(k\)

\[原式=\displaystyle\sum_{j=0}^{k}S_2(k,j)j!\sum_{i=j}^{n} C_n^iC_i^j。 \]

这里有一个结论:\(C_n^iC_i^j=C_n^jC_{n-i}^{j-i}\)

它的组合数意义是:先从n个数中取i个,再在那i个数中取j个;与先取j个,再在剩下的数中取i-j个。这两个方案是等价的。

这样,我们就得到了一个\(O(k)的式子:\displaystyle\sum_{j=0}^{k}S_2(k,j)j!C_n^j\sum_{i=j}^{n} C_{n-j}^{i-j}\)

计算\(C_n^j\)的时候可以计算\(n!*(n-1)!*...*(n-j+1)!再除以j!\)

然后\(\displaystyle\sum_{i=j}^{n} C_{n-j}^{i-j}=\sum_{d=0}^{n-j}C_{n-j}^d=2^{n-j}\)。于是这个问题就解决了。

代码:

#include<bits/stdc++.h>
#define ll long long

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

ll n,k;
ll fac[5005],inv[5005],suf[5005];
ll s[5005][5005];
const ll mod=1e9+7; 
ll ksm(ll t,ll x) {
	ll ans=1;
	for(;x;x>>=1,t=t*t%mod)
		if(x&1) ans=ans*t%mod;
	return ans;
}
ll C(int n,int m) {return fac[n]*ksm(fac[m]*fac[n-m]%mod,mod-2)%mod;}

ll cal(int n,int k) {
	if(!k) return 1;
	return suf[k-1]*inv[k]%mod;
}

int main() {
	n=Get(),k=Get();
	s[0][0]=1;
	for(int i=1;i<=k;i++)
		for(int j=1;j<=i;j++)
			s[i][j]=(s[i-1][j-1]+j*s[i-1][j])%mod;
	fac[0]=1;
	for(int i=1;i<=k;i++) fac[i]=fac[i-1]*i%mod;
	inv[k]=ksm(fac[k],mod-2);
	for(int i=k-1;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
	
	suf[0]=n;
	for(int i=1;i<=k;i++) suf[i]=suf[i-1]*(n-i)%mod;
	ll ans=0;
	int lim=min(n,k);
	for(int i=0;i<=lim;i++) {
		(ans+=s[k][i]*fac[i]%mod*cal(n,i)%mod*ksm(2,n-i)%mod)%=mod;
	}
	cout<<ans; 
	return 0;
}

posted @ 2018-11-23 16:41  hec0411  阅读(322)  评论(1编辑  收藏  举报