Codeforces 1109D. Sasha and Interesting Fact from Graph Theory

Codeforces 1109D. Sasha and Interesting Fact from Graph Theory

解题思路

这题我根本不会做,是周指导带飞我.

首先对于当前已经有 (m) 个联通块的有标号生成树的数量是

[n^{m-2}prod_{i=1}^msize_i ]

其中 (size_i) 是第 (i) 个联通块的大小.

原理就是考虑 (prufer) 编码,先把每个联通块看成一个点,那么序列中每出现一个第 (i) 联通块缩成的点,能连的边的数量是 (size[i]) ,所以序列每一位的方案数是 (sum size[i]=n),考虑每一个点的度数是在序列中的出现次数(+1),所以对于每一个联通块还要补上一条连边的方案数.

然后这个题相当于就是确定了一条链,在剩下 (n-i-2) 个联通块的基础上求有标号生产树数量,其中 (i)(a,b​) 之间的点数,根据上面的式子,可以得到答案的式子

[ans = sum_{i=0}^{n-2}inom{m-1}{i}inom{n-2}{i} imes i! imes n^{n-i-3} imes (i+2) imes m^{n-i-2} ]

code

/*program by mangoyang*/
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
	int ch = 0, f = 0; x = 0;
	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
	for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
	if(f) x = -x;
}
#define int ll
const int N = 10000005, mod = 1e9+7;
int js[N], inv[N], n, m, a, b, ans;
inline int Pow(int a, int b){
	if(b == -1) b = mod - 2;
	int ans = 1;
	for(; b; b >>= 1, a = a * a % mod)
		if(b & 1) ans = ans * a % mod;
	return ans;
}
inline int C(int x, int y){ 
	if(x < y) return 0;
	return js[x] * inv[y] % mod * inv[x-y] % mod; 
}
signed main(){
	read(n), read(m), read(a), read(b);
	js[0] = inv[0] = 1;
	for(int i = 1; i <= max(n, m); i++)
		js[i] = js[i-1] * i % mod, inv[i] = Pow(js[i], mod - 2);
	for(int i = 0; i <= n - 2; i++)
		(ans += C(m - 1, i) * C(n - 2, i) % mod * js[i] % mod * Pow(n, n - i - 3) % mod * (i + 2) % mod * Pow(m, n - i - 2) % mod) %= mod;
	cout << ans << endl;
	return 0;
}
原文地址:https://www.cnblogs.com/mangoyang/p/10415280.html