题目链接:http://codeforces.com/contest/1113/problem/F
题意:现在有一棵树,树有n个节点,每条边有一个权值,权值最大为m,现在给你两个点a, b,两点间路径的权值和是m,现在问你这棵树有多少种组成方式。
解题心得:现在假设两点间有e条边,那么就有e-1个点
- 从n-2个点中选点出来在两点间的组合方式是A(n-2, e-1)种组合方式。
- 两点间的e-1个点权值的安排方式按照隔板法有C(e-1, m-1)种。
- 剩下的n-e-1个点要放在已经组合好的这个路径上根据凯利公式有:(e+1)*n^(n-i-2)种方式。
- 以上三种组合乘起来就是e条边的答案。
枚举两点间边的数目,然后将所有方法加起来,里面要取模还需要逆元等知识。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 100;
const int MOD = 1e9 + 7;
typedef long long ll;
ll n, m, a, b;
ll mult[maxn];
void pre() {
mult[0] = 1;
for (ll i = 1; i < maxn; i++) {
mult[i] = (mult[i - 1] * i) % MOD;
}
}
ll q_pow(ll x, ll cnt) {
ll ans = 1;
x %= MOD;
if (x == 0) return 1;
while (cnt) {
if (cnt & 1) ans = (ans * x) % MOD;
x = (x * x) % MOD;
cnt >>= 1;
}
return ans;
}
int main() {
freopen("1.in", "r", stdin);
pre();
while (scanf("%lld%lld%lld%lld", &n, &m, &a, &b) != EOF) {
ll ans = 0;
for (ll i = 1; i <= min(m, n - 1); i++) {
//A(i-1, n-2)
ll temp1 = mult[n - 2] * q_pow(mult[n - i - 1], MOD - 2) % MOD;
//C(i-1, m-1)
ll temp2 = mult[m - 1] % MOD * q_pow(mult[m - i], MOD - 2) % MOD * q_pow(mult[i - 1], MOD - 2) % MOD;
//m^(n-i-1)
ll temp3 = q_pow(m, n - i - 1) % MOD;
//(i+1)*n^(n-i-2)
ll temp4 = (i + 1) % MOD * (n -i - 2 < 0 ? q_pow(q_pow(n, -(n - i - 2)), MOD - 2) : q_pow(n, n - i - 2)) % MOD;
ans = ans + temp1 * temp2 % MOD * temp3 % MOD * temp4 % MOD;
}
printf("%lld\n", ans);
}
return 0;
}