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

猜你喜欢

转载自www.cnblogs.com/LSlzf/p/12209673.html