[CodeForces 1109D] Sasha and Interesting Fact from Graph Theory(广义 Cayley 定理 + 组合数学) | 错题本

文章目录

题目

[CodeForces 1109D] Sasha and Interesting Fact from Graph Theory

分析

a , b a, b a,b 不影响答案,不妨设 a = 1 , b = 2 a = 1, b = 2 a=1,b=2,枚举 a , b a, b a,b 之间的边数 i ∈ [ 1 , n − 1 ] i \in [1, n -1] i[1,n1],隔板法可得链 a − b a - b ab 的方案数为 A n − 2 i − 1 ⋅ C m − 1 i − 1 A_{n - 2}^{i - 1} \cdot C_{m - 1}^{i - 1} An2i1Cm1i1(中间的点编号可以任意取,所以是 A n − 2 i − 1 A_{n - 2}^{i - 1} An2i1)然后考虑剩下的点和边,首先边权随意: A n − 2 i − 1 ⋅ C m − 1 i − 1 ⋅ m n − 1 − i A_{n - 2}^{i - 1} \cdot C_{m - 1}^{i - 1} \cdot m^{n - 1 - i} An2i1Cm1i1mn1i 然后考虑剩下的点,这个树是这个样子的:树的形状
因此接下来我们只需要求 n n n 个点构成一个的含有 i + 1 i + 1 i+1 棵树的森林的数量。根据广义 Cayley 定理, n n n 个点构成的含有 k k k 棵树的森林数量为 k ⋅ n n − k − 1 k \cdot n^{n - k - 1} knnk1。因此 n n n 个点构成一个的含有 i + 1 i + 1 i+1 棵树的森林的数量即为 ( i + 1 ) ⋅ n n − i − 2 (i + 1) \cdot n^{n - i - 2} (i+1)nni2

证明:
将链 a − b a - b ab 缩为一个点,那么这个树的数量为 n n − i − 2 n^{n - i - 2} nni2,再考虑把上图中的三角形轮换一圈(因为 n n − i − 2 n^{n - i - 2} nni2 算的是各个三角形的圆排列,现在把它转换成一般排列),答案即为 ( i + 1 ) n n − i − 2 (i+1)n^{n - i - 2} (i+1)nni2

因此答案为 ∑ i = 1 n − 1 A n − 2 i − 1 C m − 1 i − 1 ( i + 1 ) n n − i − 2 m n − 1 − i \sum_{i = 1}^{n - 1} A_{n - 2}^{i - 1} C_{m - 1}^{i - 1}(i + 1)n^{n - i - 2}m^{n - 1 - i} i=1n1An2i1Cm1i1(i+1)nni2mn1i

代码

#include <bits/stdc++.h>

const int MAXN = 1000000;
const int MOD = 1000000007;

int N, M, A1, B1;
int Fac[MAXN + 5], Inv[MAXN + 5];
int PowN[MAXN + 5], PowM[MAXN + 5];

inline int Add(int x, const int &y) {
    x += y; if (x >= MOD) x -= MOD; return x;
}

inline int Mul(const int &x, const int &y) {
    return (long long)x * y % MOD;
}

int Pow(int x, int y) {
    int ret = 1;
    while (y) {
        if (y & 1)
            ret = Mul(ret, x);
        x = Mul(x, x);
        y >>= 1;
    }
    return ret;
}

int A(int n, int m) {
    return Mul(Fac[n], Inv[n - m]);
}

int C(int n, int m) {
    if (m > n) return 0;
    return Mul(Fac[n], Mul(Inv[m], Inv[n - m]));
}

int main() {
    scanf("%d%d%d%d", &N, &M, &A1, &B1);
    int Max = std::max(N, M);
    Fac[0] = PowN[0] = PowM[0] = 1;
    for (int i = 1; i <= Max; i++) {
        Fac[i] = Mul(Fac[i - 1], i);
        PowN[i] = Mul(PowN[i - 1], N);
        PowM[i] = Mul(PowM[i - 1], M);
    }
    Inv[Max] = Pow(Fac[Max], MOD - 2);
    for (int i = Max - 1; i >= 0; i--)
        Inv[i] = Mul(Inv[i + 1], i + 1);
    int Ans = Mul(C(M - 1, N - 2), A(N - 2, N - 2));
    for (int i = 1; i <= N - 2; i++)
        Ans = Add(Ans, Mul(A(N - 2, i - 1), Mul(C(M - 1, i - 1), Mul(i + 1, Mul(PowN[N - i - 2], PowM[N - 1 - i])))));
    printf("%d", Ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值