[CF932E] Team Work

问题描述

You have a team of N people. For a particular task, you can pick any non-empty subset of people. The cost of having x people for the task is \(x^{k}\)

Output the sum of costs over all non-empty subsets of people.

输入格式

Only line of input contains two integers \(N (1<=N<=10^{9})\) representing total number of people and \(k (1<=k<=5000)\).

输出格式

Output the sum of costs for all non empty subsets modulo \(10^{9}+7\) .

样例输入

1 1

样例输出

1

题目大意

\(\sum_{i=1}^n C(n,i) \times i^k\)

解析

首先,我们要知道这样一个跟斯特林数有关的公式:

\[n^k=\sum_{i=0}^{n} \begin{Bmatrix}i\\k \end{Bmatrix} \times C_n^i\times i! \]

带入原式,我们有:

\[\sum_{i=1}^n C(n,i) \times i^k = \sum_{i=1}^nC_n^i\times \sum_{j=0}^{i}\begin{Bmatrix}j\\k \end{Bmatrix}\times C_i^j\times j!\\ \]

对于每一个斯特林数,我们把他提出来,计算斯特林数前的系数:

\[\sum_{i=1}^nC_n^i\times \sum_{j=0}^{i}\begin{Bmatrix}j\\k \end{Bmatrix}\times C_i^j\times j!=\sum_{j=0}^{k}\begin{Bmatrix}j\\k \end{Bmatrix}\times \sum_{i=0}^kC_n^i\times C_i^j\times j! \]

对于后面的系数部分,我们运用组合意义对其进行化简。这个式子相当于计算\(k\)次选择,第\(i\)次从\(n\)个球中选择\(i\)个球,再从\(i\)个球中选择\(j\)个进行排列的方案数。等价于我们可以直接选择\(j\)个球进行排列,其他的球可以选或者不选。所以,我们有:

\[\begin{align} \sum_{i=0}^kC_n^i\times C_i^j\times j!&=C_n^j\times j!\times2^{n-j}\\ &=\frac{n!}{(n-j)!}\times 2^{n-j} \end{align} \]

所以,原式等于

\[\sum_{j=0}^{k}\begin{Bmatrix}j\\k \end{Bmatrix}\times\frac{n!}{(n-j)!}\times 2^{n-j} \]

斯特林数可以预处理,2的幂次可以用快速幂解决。至于中间的阶乘,因为\(j\)的变化量只有\(k\),是可以预处理的。那么这道题就完成了。

代码

#include <iostream>
#include <cstdio>
#define int long long
#define N 5002
using namespace std;
const int mod=1000000007;
int n,k,i,j,S[N][N],C[N];
int read()
{
	char c=getchar();
	int w=0;
	while(c<'0'||c>'9') c=getchar();
	while(c<='9'&&c>='0'){
		w=w*10+c-'0';
		c=getchar();
	}
	return w;
}
int poww(int a,int b)
{
	long long ans=1,base=a;
	while(b){
		if(b&1) ans=ans*base%mod;
		base=base*base%mod;
		b>>=1;
	}
	return ans;
}
signed main()
{
	n=read();k=read();
	S[0][0]=1;
	for(i=1;i<=k;i++){
		for(j=1;j<=i;j++) S[i][j]=(1LL*S[i-1][j-1]+S[i-1][j]*j%mod)%mod;
	}
	C[0]=1;
	for(i=1;i<=k;i++) C[i]=1LL*C[i-1]*(n-i+1)%mod;
	long long ans=0;
	for(i=0;i<=min(n,k);i++) ans=(ans+1LL*S[k][i]*C[i]%mod*poww(2,n-i)%mod)%mod;
	printf("%lld\n",ans);
	return 0;
}
posted @ 2020-01-18 17:27  CJlzf  阅读(131)  评论(0编辑  收藏  举报