E. Team Work
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
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 xk.
Output the sum of costs over all non-empty subsets of people.
Input
Only line of input contains two integers N (1 ≤ N ≤ 109) representing total number of people and k (1 ≤ k ≤ 5000).
Output
Output the sum of costs for all non empty subsets modulo 109 + 7.
Examples
input
1 1
output
1
input
3 2
output
24
Note
In the first example, there is only one non-empty subset {1} with cost 11 = 1.
In the second example, there are seven non-empty subsets.
- {1} with cost 12 = 1
- {2} with cost 12 = 1
- {1, 2} with cost 22 = 4
- {3} with cost 12 = 1
- {1, 3} with cost 22 = 4
- {2, 3} with cost 22 = 4
- {1, 2, 3} with cost 32 = 9
The total cost is 1 + 1 + 4 + 1 + 4 + 4 + 9 = 24.
题意:
你可以在n个人中选出非空的i个人子集,这个子集的权值为i的k次,问这n个人可以得到的权值为多少。
做法:
很明显求的是 ,但是由于n很大,直接暴力肯定是T的,注意到k的范围只有5000,所以可以用dp来做。利用二项式定理展开 进行k次求导,每次求导后再次乘上x,x次求导之后把x变为1则可获得想求的值,居然见代码
代码如下:
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll n,k,ans,dp[5500][5500];//dp[i][j]表示第i次求导后x为j时的系数
ll quick(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=ans*a%mod;
a=a*a%mod;
b/=2;
}
return ans;
}
int main(){
ans=0;
scanf("%lld%lld",&n,&k);
dp[1][1]=n;//第一次求导得到一项,系数为n
for(int i=1;i<k;i++){
for(int j=1;j<=i;j++){
dp[i+1][j]+=dp[i][j]*j;//i次求导后第j项为x的j次,再求导,得到下一次的系数
dp[i+1][j]%=mod;
dp[i+1][j+1]+=dp[i][j]*(n-j);//i次求导后(1+x)的次数为n-j,进行求导后加入x的j+1次中
dp[i+1][j+1]%=mod;
}
}
for(int i=1;i<=k;i++){
ans=(ans+quick(2,n-i)*dp[k][i]%mod)%mod;//计算k次求导后,每一项的值,此处x代入1
}
printf("%lld\n",ans%mod);
return 0;
}