[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;
}