当前位置: 代码迷 >> 综合 >> CodeForces【组合数学】1109D-Sasha and Interesting Fact from Graph Theory
  详细解决方案

CodeForces【组合数学】1109D-Sasha and Interesting Fact from Graph Theory

热度:24   发布时间:2023-11-21 06:51:38.0

CodeForces 1109D Sasha and Interesting Fact from Graph Theory

◇题目传送门◆

题目大意

给定NNN个结点,编号为1,2,…,N1,2,\ldots,N1,2,,N,再给定两个点A,BA,BA,B,要求这两个点的距离为MMM,且树中的每一条边权均为111MMM的整数,求这样能构造的树的方案数。

分析

显然可以知道A,BA,BA,B是什么值对整个答案的计算没有影响。

考虑按如下方法构造:

即先构造出一条有xxx个结点链,再在这条链上随意连接子树。

这个链的方案数为AN?2x?1A_{N-2}^{x-1}AN?2x?1?

那么在这条链上,分配的方案数为CM?1x?1C_{M-1}^{x-1}CM?1x?1?

这一部分的方案数为AN?2x?1?CM?1x?1A_{N-2}^{x-1}\cdot C_{M-1}^{x-1}AN?2x?1??CM?1x?1?

考虑计算剩余的结点的方案数:

利用Prufer序列的性质,我们将构造出来的链顺序标上N?x,N?x+1,?,NN-x,N-x+1,\cdots,NN?x,N?x+1,?,N,这样一来,将我们构造出的树的Prufer序列的最后x?2x-2x?2位一定就是我们所构造出来的链。

那么考虑前N?xN-xN?x个结点,它们在序列中的顺序是随意的,不难得出这N?xN-xN?x个结点随意排列的方案数为NN?x?2N^{N-x-2}NN?x?2。此外,又由于这个序列中除了最后一个点是固定的,这个序列的剩余的点必定是任意值,所以这个方案数为(x+1)?NN?x?2(x+1)\cdot N^{N-x-2}(x+1)?NN?x?2

好像网上有些说可以用广义Cayley定理来解决这个问题。。。

最后考虑边权,因为我们事先已经固定了xxx条边的边权,其他的边随意选取即可,所以这个方案数就是MN?x?1M^{N-x-1}MN?x?1

所以最后的总方案数为∑i=1N?1AN?2x?1?CM?1x?1?(x+1)?NN?x?2?MN?x?1\sum_{i=1}^{N-1}{}A_{N-2}^{x-1}\cdot C_{M-1}^{x-1}\cdot(x+1)\cdot N^{N-x-2}\cdot M^{N-x-1}i=1N?1?AN?2x?1??CM?1x?1??(x+1)?NN?x?2?MN?x?1

此外,注意到i=N?1i=N-1i=N?1时有一项的次数是负数,特判一下就是了。

参考代码

#include <cstdio>
#include <algorithm>
using namespace std;typedef long long ll;
const int Maxn = 1e6;
const int Mod = 1e9 + 7;ll fac[Maxn + 5], inv_fac[Maxn + 5];
ll QuickPow(ll a, ll k) {
    ll ret = 1;while(k) {
    if(k & 1) ret = ret * a % Mod;a = a * a % Mod;k >>= 1;}return ret;
}
void Init() {
    fac[0] = inv_fac[0] = 1;for(int i = 1; i <= Maxn; i++)fac[i] = fac[i - 1] * i % Mod;inv_fac[Maxn] = QuickPow(fac[Maxn], Mod - 2);for(int i = Maxn - 1; i >= 1; i--)inv_fac[i] = inv_fac[i + 1] * (i + 1) % Mod;
}
ll C(int n, int m) {
    if(n < 0 || m < 0 || n < m) return 0;return fac[n] * inv_fac[m] % Mod * inv_fac[n - m] % Mod;
}
ll A(int n, int m) {
    if(n < 0 || m < 0 || n < m) return 0;return fac[n] * inv_fac[n - m] % Mod;
}int N, M;int main() {
    
#ifdef LOACLfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
#endifInit();int t1, t2;scanf("%d %d %d %d", &N, &M, &t1, &t2);ll ans = 0;for(int i = 1; i < N; i++) {
    ll tmp = A(N - 2, i - 1) * C(M - 1, i - 1) % Mod;tmp = tmp * QuickPow(M, N - i - 1) % Mod;if(i != N - 1) tmp = tmp * QuickPow(N, N - i - 2) % Mod * (i + 1) % Mod;ans = (ans + tmp) % Mod;}printf("%lld\n", ans);return 0;
}
  相关解决方案