CF932E Team Work 第二类斯特林数+组合数学

    科技2022-08-31  113

    文章目录

    一.题目二.Solution三.CodeThanks!

    一.题目

    N ( 1 ≤ N ≤ 1 0 9 ) N(1≤N≤10^9) N(1N109)个不同的人,你从中选择 x x x( x x x至少为 1 1 1)个人去完成一个团队任务,代价为 x k ( 1 ≤ k ≤ 5000 ) x^k(1≤k≤5000) xk(1k5000)。 求所有组队方案的总代价。 传送门

    二.Solution

    不难发现,这道题目可以转化成: ∑ i = 1 n C n i ∗ i k ∑_{i=1}^nC_{n}^{i}∗i^ k i=1nCniik 但这要超时,怎么办呢?我们可以通过第二类斯特林数、组合数学、阶乘来分解 i k i^k ik i k = ∑ j = 0 k S k j ∗ j ! ∗ C i j i^k=\sum_{j=0}^{k}S_{k}^{j}*j!*C_{i}^{j} ik=j=0kSkjj!Cij 我们可以这样理解:把k个球放进i个盒子里,选择 0 ∼ k 0\sim k 0k个盒子放球,每次选 j j j个盒子,把球分成 j j j堆,在给这些堆来一个全排列放进盒子里,就涵盖了所有放球情况。 然后继续来分解: ∑ i = 1 n C n i ∑ j = 0 k S k j ∗ j ! ∗ C i j \sum_{i=1}^{n}C_{n}^{i}\sum_{j=0}^{k}S_{k}^{j}*j!*C_{i}^{j} i=1nCnij=0kSkjj!Cij S k j S_{k}^{j} Skj j ! j! j!对于内层循环是定值,可以提到外面来: → ∑ j = 0 k S k j ∗ j ! ∑ i = 1 n C n i ∗ C i j \rightarrow \sum_{j=0}^{k}S_{k}^{j}*j!\sum_{i=1}^{n}C_{n}^{i}*C_{i}^{j} j=0kSkjj!i=1nCniCij 然后后面的 C n i ∗ C i j C_{n}^{i}*C_{i}^{j} CniCij可以通过组合数的一个性质: C n m ∗ C m r = C n r ∗ C n − r m − r C_{n}^{m}*C_{m}^{r}=C_{n}^{r}*C_{n-r}^{m-r} CnmCmr=CnrCnrmr

    证明: C n m ∗ C m r C_{n}^{m}*C_{m}^{r} CnmCmr = m ! ∗ ( n − m ) ! n ! ∗ r ! ∗ ( m − r ) ! m ! =\frac{m!*(n-m)!}{n!}*\frac{r!*(m-r)!}{m!} =n!m!(nm)!m!r!(mr)! = ( n − m ) ! ∗ r ! ∗ ( m − r ) ! n ! =\frac{(n-m)!*r!*(m-r)!}{n!} =n!(nm)!r!(mr)! = ( n − m ) ! ∗ r ! ∗ ( m − r ) ! ∗ ( n − r ) ! n ! ∗ ( n − r ) ! =\frac{(n-m)!*r!*(m-r)!*(n-r)!}{n!*(n-r)!} =n!(nr)!(nm)!r!(mr)!(nr)! = r ! ∗ ( n − r ) ! n ! ∗ ( m − r ) ! ∗ ( n − m ) ! ( n − r ) ! =\frac{r!*(n-r)!}{n!}*\frac{(m-r)!*(n-m)!}{(n-r)!} =n!r!(nr)!(nr)!(mr)!(nm)! = C n r ∗ C n − r m − r =C_{n}^{r}*C_{n-r}^{m-r} =CnrCnrmr

    于是我们又可以继续推: → ∑ j = 0 k S k j ∗ j ! ∗ C n j ∑ i = 1 n C n − j i − j \rightarrow \sum_{j=0}^{k}S_{k}^{j}*j!*C_{n}^{j}\sum_{i=1}^{n}C_{n-j}^{i-j} j=0kSkjj!Cnji=1nCnjij 然后让我们来观察一下 ∑ i = 1 n C n − j i − j \sum_{i=1}^{n}C_{n-j}^{i-j} i=1nCnjij,其实当 i < j i<j i<j时没有意义,若 i > = j i>=j i>=j就将 i − j i-j ij视为 t t t,则相当于求 ∑ t = 0 n − j C n − j t \sum_{t=0}^{n-j}C_{n-j}^{t} t=0njCnjt,这显而易见等于 2 n − j 2^{n-j} 2nj,最后就化为: → ∑ j = 0 k S k j ∗ j ! ∗ C n j ∗ 2 n − j \rightarrow \sum_{j=0}^{k}S_{k}^{j}*j!*C_{n}^{j}*2^{n-j} j=0kSkjj!Cnj2nj n太大?我们只用预处理第二类斯特林数,其他的东西跟随着循环递推就行了。So easy!

    三.Code

    #include <cstdio> #include <cstring> #include <iostream> #include <cmath> using namespace std; #define LL long long #define M 5005 const LL mod = 1e9 + 7; LL S[M][M], ans, n, k; LL qkpow (LL x, LL y){ LL res = 1; while (y){ if (y & 1) res = res * x % mod; x = x * x % mod; y >>= 1; } return res; } void stirlin2 (int now){ for (int i = 1; i <= now; i ++){ S[i][0] = 0; S[i][i] = S[i][1] = 1; for (int j = 2; j < i; j ++){ S[i][j] = (S[i - 1][j - 1] + S[i - 1][j] * 1ll * j % mod) % mod; } } } int main (){ scanf ("%lld %lld", &n, &k); stirlin2 (k); LL C = 1, fac = 1, mi = qkpow (2, n), inv = qkpow (2, mod - 2); for (int i = 1; i <= k; i ++){ C = C * (n - i + 1) % mod * qkpow (i, mod - 2) % mod; fac = fac * i % mod; mi = mi * inv % mod; ans = (ans + S[k][i] * mi % mod * fac % mod * C % mod) % mod; } printf ("%lld\n", ans); return 0; }

    Thanks!

    Processed: 0.008, SQL: 9