题目
[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,n−1],隔板法可得链
a
−
b
a - b
a−b 的方案数为
A
n
−
2
i
−
1
⋅
C
m
−
1
i
−
1
A_{n - 2}^{i - 1} \cdot C_{m - 1}^{i - 1}
An−2i−1⋅Cm−1i−1(中间的点编号可以任意取,所以是
A
n
−
2
i
−
1
A_{n - 2}^{i - 1}
An−2i−1)然后考虑剩下的点和边,首先边权随意:
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}
An−2i−1⋅Cm−1i−1⋅mn−1−i 然后考虑剩下的点,这个树是这个样子的:
因此接下来我们只需要求
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}
k⋅nn−k−1。因此
n
n
n 个点构成一个的含有
i
+
1
i + 1
i+1 棵树的森林的数量即为
(
i
+
1
)
⋅
n
n
−
i
−
2
(i + 1) \cdot n^{n - i - 2}
(i+1)⋅nn−i−2。
证明:
将链 a − b a - b a−b 缩为一个点,那么这个树的数量为 n n − i − 2 n^{n - i - 2} nn−i−2,再考虑把上图中的三角形轮换一圈(因为 n n − i − 2 n^{n - i - 2} nn−i−2 算的是各个三角形的圆排列,现在把它转换成一般排列),答案即为 ( i + 1 ) n n − i − 2 (i+1)n^{n - i - 2} (i+1)nn−i−2。
因此答案为 ∑ 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=1∑n−1An−2i−1Cm−1i−1(i+1)nn−i−2mn−1−i
代码
#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;
}