求$\sum_{i=0}^nC_n^ii^k$。n<=1e9,k<=5000。
方法一:大力推公式
$\sum_{i=0}^nC_n^ii^k$
闪一句:幂转斯二林(第二类斯特林数)为什么叫斯二林呢因为第一类叫斯大林!
$=\sum_{i=0}^nC_n^i\sum_{j=0}^{k}S(k,j)A_i^j$
$=\sum_{i=0}^n\frac{n!}{i!(n-i)!}\sum_{j=0}^kS(k,j)\frac{i!}{(i-j)!}$
$=n!\sum_{i=0}^n\sum_{j=0}^kS(k,j)\frac{1}{(n-i)!(i-j)!}$
闪一句:重要!移花接木法,见到下面有个$(n-i)!(i-j)!$,上面立即配个$(n-j)!$,才能把j分离出来
$=n!\sum_{i=0}^n\sum_{j=0}^kS(k,j)C_{n-j}^{n-i}\frac{1}{(n-j)!}$
$=n!\sum_{j=0}^k S(k,j)\frac{1}{(n-j)!}\sum_{i=0}^nC_{n-j}^{n-i}$
$=\sum_{j=0}^k S(k,j)\frac{n!}{(n-j)!}2^{n-j}$
搞定。这样的话可以出K=1e5来考斯特林预处理。这里只写暴力。
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cstdio> 5 //#include<map> 6 #include<math.h> 7 //#include<time.h> 8 //#include<complex> 9 #include<algorithm> 10 using namespace std; 11 12 int n,K; 13 #define maxn 5011 14 const int mod=1e9+7; 15 int dmi[maxn],two[maxn],str[maxn][maxn]; 16 int powmod(int a,int b) 17 { 18 int ans=1; 19 while (b) 20 { 21 if (b&1) ans=1ll*ans*a%mod; 22 a=1ll*a*a%mod; b>>=1; 23 } 24 return ans; 25 } 26 void pre(int n,int m) 27 { 28 str[0][0]=1; 29 for (int i=1;i<=n;i++) 30 { 31 str[i][0]=0; 32 for (int j=1;j<=i;j++) str[i][j]=(str[i-1][j-1]+1ll*j*str[i-1][j])%mod; 33 } 34 dmi[0]=1; for (int i=1;i<=n;i++) dmi[i]=dmi[i-1]*1ll*(m-i+1)%mod; 35 two[0]=powmod(2,m); for (int i=1,tmp=(mod+1)>>1;i<=n;i++) two[i]=two[i-1]*1ll*tmp%mod; 36 } 37 int main() 38 { 39 scanf("%d%d",&n,&K); 40 pre(K,n); 41 int ans=0; 42 for (int i=1;i<=K;i++) ans=(ans+str[K][i]*1ll*dmi[i]%mod*two[i])%mod; 43 printf("%d\n",ans); 44 return 0; 45 }
方法二:组合意义转换
问题即求:对每个集合,从中可重复地挑K个人,问方案。
那咋不能先挑人再统计集合啊?挑人之后,一个满足这挑人方案的集合有多少种呢?首先挑的这些人肯定是要有的,其他人随意。但注意,这里挑人是重复的,所以挑的人数不等于挑的人种,就是把n看成n种人。那假设挑了k个人,j种人,对答案的贡献是$2^{n-j}$。那挑i个人,j种人,有多少种方案?大力dp,$f(i,j)=f(i-1,j)*j+f(i-1,j-1)*(n-j+1)$。
代码?自己写。