CodeForces - 1109D Sasha and Interesting Fact from Graph Theory

题意:

给定 n n n 个带标结点,边权范围 [ 1 , m ] [1, m] [1,m],再给定两点 a , b a, b a,b,求所有可能的 a , b a,b a,b 路径上边权和为 m m m 的树的种数。 ( n , m ≤ 1 0 6 ) (n, m \leq 10^6) (n,m106)

链接:

https://codeforces.com/contest/1109/problem/D

解题思路:

a , b a, b a,b 路径上共有 s s s 个点,从剩余 n − 2 n - 2 n2 个点中选出 s s s 排列在 a b ab ab 路径上的方案数为 A n − 2 s − 2 A_{n - 2}^{s - 2} An2s2,将 s − 1 s - 1 s1 条边权赋值后和为 m m m 的方案数为 C m − 1 s − 2 C_{m - 1}^{s - 2} Cm1s2 (隔板法, m m m 个球 m − 1 m - 1 m1 个空,插入 s − 2 s - 2 s2 个板,得到 s − 1 s - 1 s1 个划分块),剩余边的边权方案数为 m n − s m^{n - s} mns,剩余点生成的森林可以任意拼接在 a b ab ab 路径上,由 C a y l e y ′ s   f o r m u l a Cayley's~formula Cayleys formula 可知, n n n 个带标结点生成的具有 s s s 棵树的森林且 s s s 个指定结点分属不同分量的方案有 s n n − s − 1 sn^{n - s - 1} snns1 种。综上,
a n s = A n − 2 s − 2 ∗ C m − 1 s − 2 ∗ m n − s ∗ s n n − s − 1 , s ∈ [ 2 , n ] ans = A_{n - 2}^{s - 2} * C_{m - 1}^{s - 2} * m^{n - s} * sn^{n - s - 1}, s \in [2, n] ans=An2s2Cm1s2mnssnns1,s[2,n]

参考代码:
#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 1e6 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

ll inv[maxn], fac[maxn], finv[maxn], pwn[maxn], pwm[maxn];
int n, m, a, b;

ll comb(int n, int m){

    if(m > n) return 0;
    return fac[n] * finv[m] % mod * finv[n - m] % mod;
}

int main(){

    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n >> m >> a >> b;
    inv[1] = fac[0] = finv[0] = pwn[0] = pwm[0] = 1;
    int lim = max(n, m);
    for(int i = 1; i <= lim; ++i){

        inv[i] = i == 1 ? 1 : (mod - mod / i) * inv[mod % i] % mod;
        fac[i] = fac[i - 1] * i % mod;
        finv[i] = finv[i - 1] * inv[i] % mod;
        pwn[i] = pwn[i - 1] * n % mod;
        pwm[i] = pwm[i - 1] * m % mod;
    }
    ll ret = 0;
    for(int i = 2; i <= n; ++i){

        ll tmp = comb(n - 2, i - 2) * fac[i - 2] % mod * comb(m - 1, i - 2) % mod * i % mod * (i == n ? inv[i] : pwn[n - i - 1]) % mod * pwm[n - i] % mod;
        ret = (ret + tmp) % mod;
    }
    cout << ret << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值