题意
询问有多少个 N N N个点, M M M条边的有向图,从 1 1 1号点到达 N N N号点需要经过至少 N − 1 N-1 N−1条边。该有向图中可以包含重边和自环。方案数 % 1000000009 \%1000000009 %1000000009。
思路
因为至少是 N − 1 N-1 N−1条边,所以这构成了一条链,我们要在这链里加边且不是捷径边。
一共可以加入 N 2 N^2 N2条边,捷径边的边数有 C N − 1 2 C_{N-1}^{2} CN−12条边,那么还能加进去的边还有 N 2 − C N − 1 2 N^2-C_{N-1}^{2} N2−CN−12。
因为图中有 M M M条边,用了 N − 1 N-1 N−1条边,所以还剩 M − N + 1 M-N+1 M−N+1条边,我们要把这能加进的 N 2 − C N − 1 2 N^2-C_{N-1}^{2} N2−CN−12边放到这里面。
这里给出一个公式,把 N N N个相同的元素放进 M M M个桶的方案数为 C N + M − 1 N C_{N+M-1}^{N} CN+M−1N
然后我们就可以套公式求出答案了,然后取模就直接算逆元。
代码
#include<cstdio>
const int P = 1e9 + 7;
int n, m;
int fact[10001];
int power(int a, int b) {
int result = 1;
a %= P;
for (; b; b >>= 1) {
if (b & 1) result = (long long)result * a % P;
a = (long long)a * a % P;
}
return result;
}
long long C(int n, int m) {
long long a = 1, b = 1;
for (int i = n; i > n - m; i--)
a = a * i % P;
for (int i = 1; i <= m; i++)
b = b * power(i, P - 2) % P;
return a * b % P;
}
int main() {
scanf("%d %d", &n, &m);
fact[0] = 1;
for (int i = 1; i <= n - 2; i++)
fact[i] = (long long)fact[i - 1] * i % P;
printf("%d", C(n * n - C(n - 1, 2) - 1 + m - n + 1, m - n + 1) * fact[n - 2] % P);
}