Codeforces932E. Team Work

求$sum_{i=0}^nC_n^ii^k$。n<=1e9,k<=5000。

方法一:大力推公式

$sum_{i=0}^nC_n^ii^k$

闪一句:幂转斯二林(第二类斯特林数)为什么叫斯二林呢因为第一类叫斯大林!

$=sum_{i=0}^nC_n^isum_{j=0}^{k}S(k,j)A_i^j$

$=sum_{i=0}^nfrac{n!}{i!(n-i)!}sum_{j=0}^kS(k,j)frac{i!}{(i-j)!}$

$=n!sum_{i=0}^nsum_{j=0}^kS(k,j)frac{1}{(n-i)!(i-j)!}$

闪一句:重要!移花接木法,见到下面有个$(n-i)!(i-j)!$,上面立即配个$(n-j)!$,才能把j分离出来

$=n!sum_{i=0}^nsum_{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
",ans);
44     return 0;
45 }
View Code

方法二:组合意义转换

问题即求:对每个集合,从中可重复地挑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)$。

代码?自己写。

原文地址:https://www.cnblogs.com/Blue233333/p/8487091.html