思路
第二类斯特林数和组合数推式子的题目
题目要求(sum_{i=1}^n left(egin{matrix}n \ i end{matrix} ight) i^k)
一个性质
第二类斯特林数有这样的性质
[n^k=sum_{i=0}^n left{egin{matrix}k \ i end{matrix}
ight}i!left(egin{matrix}n \ i end{matrix}
ight)
]
就是相当于枚举取哪i个可区分的盒子,再把k个球放进去,方案数总和就等于每个球都任意放的方案数
推式子
因为(i=0)时,后面的贡献是0,所以不妨变为(sum_{i=0}^n left(egin{matrix}n \ i end{matrix} ight) i^k)
然后代入性质,得到
[egin{align}&sum_{i=0}^n left( egin{matrix}n\iend{matrix}
ight)i^k \ =&sum_{i=0}^n left( egin{matrix}n\iend{matrix}
ight)sum_{j=0}^i left{ egin{matrix}k\jend{matrix}
ight}j!left( egin{matrix}i\jend{matrix}
ight) \=&sum_{i=0}^n left( egin{matrix}n\iend{matrix}
ight)sum_{j=0}^i left{ egin{matrix}k\jend{matrix}
ight}frac{i!}{(n-j)!}\=&n!sum_{i=0}^n frac{1}{(n-i)!}sum_{j=0}^i left{ egin{matrix}k\jend{matrix}
ight}frac{1}{(n-j)!}\=&n!sum_{i=0}^n sum_{j=0}^i left{ egin{matrix}k\jend{matrix}
ight}frac{1}{(n-i)!(n-j)!}\=&n!sum_{j=0}^nleft{ egin{matrix}k\jend{matrix}
ight} sum_{i=j}^nleft( egin{matrix}n-i\n-jend{matrix}
ight) frac{1}{(n-j)!} \=&n!sum_{i=0}^n sum_{j=0}^i left{ egin{matrix}k\jend{matrix}
ight}frac{1}{(n-i)!(n-j)!}\=&sum_{j=0}^nfrac{n!}{(n-j)!}left{ egin{matrix}k\jend{matrix}
ight} sum_{i=j}^nleft( egin{matrix}n-i\n-jend{matrix}
ight)\=&sum_{j=0}^nfrac{n!}{(n-j)!}left{ egin{matrix}k\jend{matrix}
ight} sum_{i=0}^nleft( egin{matrix}n-i\n-jend{matrix}
ight) \=&sum_{j=0}^nfrac{n!}{(n-j)!}left{ egin{matrix}k\jend{matrix}
ight}2^{n-j}\=&sum_{j=0}^kfrac{n!}{(n-j)!}left{ egin{matrix}k\jend{matrix}
ight}2^{n-j}end{align}
]
然后(O(k^2))的处理就好了
代码
不知道为什么n,k不能声明到S函数的上方
#include <cstdio>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int MOD = 1000000007;
int s[5010][5010]={0};
bool vis[5010][5010]={0};
int my_pow(int a,int b){
int ans=1;
while(b){
if(b&1)
ans=(1LL*ans*a)%MOD;
a=(1LL*a*a)%MOD;
b>>=1;
}
return ans;
}
int S(int n,int k){
// printf("n=%lld k=%lld
",n,k);
if(vis[n][k])
return s[n][k];
vis[n][k]=true;
if(n==0&&k==0)
return s[n][k]=1;
else if(n==0||k==0)
return s[n][k]=0;
return s[n][k]=(S(n-1,k-1)%MOD+k*S(n-1,k)%MOD)%MOD;
}
int n,k;
signed main(){
scanf("%lld %lld",&n,&k);
// printf("%lld %lld
",n,k);
int ans=0;
int mid=1;
for(int i=0;i<=min(k,n);i++){
ans=(ans+mid*S(k,i)%MOD*my_pow(2,n-i)%MOD)%MOD;
mid=(mid*(n-i))%MOD;
}
printf("%lld
",ans);
return 0;
}