1. 程式人生 > 其它 >King's Colors 題解

King's Colors 題解

link
題意:給出一個含有 \(n\) 個節點的樹,以及 \(k\) 個顏色,詢問有多少種方式正好用 \(k\) 個顏色給樹染色,並且任意兩個相鄰的節點顏色不同。


拿到這道題,我剛開始考慮的是從兒子開始考慮父親。但是這樣會出現一個問題,兒子顏色重複的數量決定這個父親的取值數量的多少。於是不好控制。
但是其實換個角度(trick),考慮從父親開始考慮兒子,發現兒子有 \(k-1\) 種取值,則整棵樹有 \(k*(k-1)^{n-1}\) 個取值,但是這樣計算出來可能用不完 \(k\) 個顏色。
於是設 \(F_k=k*(k-1)^{n-1}\) 表示最多用 \(k\) 個顏色的方案數,\(f_k\)

表示恰好用 \(k\) 個顏色的方案數。可以寫出:\(F_k=\sum_{i=0}^k \binom k i f_i\),妥妥的二項式反演,得出 \(f_k=\sum_{i=0}^k(-1)^{k-i}\binom {k} {i}i*(i-1)^{n-1}\)。答案即為 \(f_k\)

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#define LL long long
using namespace std;
const int MAXN = 2505, Mod = 1e9 + 7;
int n, k;
LL jc[MAXN], inv[MAXN], ans;
LL Qpow(LL x, int y) {
	LL ans = 1;
	for(; y; y >>= 1) {
		if(y & 1) ans = ans * x % Mod;
		x = x * x % Mod;
	}
	return ans;
}
LL C(int x, int y) {
	if(x < 0 || y < 0 || x < y) return 0;
	return jc[x] * inv[y] % Mod * inv[x - y] % Mod;
}
int main() {
	int x;
	scanf("%d%d", &n, &k); jc[0] = 1;
	for(int i = 1; i <= k; i ++) jc[i] = jc[i - 1] * i % Mod;
	inv[k] = Qpow(jc[k], Mod - 2);
	for(int i = k - 1; i >= 0; i --) inv[i] = inv[i + 1] * (i + 1) % Mod;
	for(int i = 2; i <= n; i ++) scanf("%d", &x); 
	for(int i = 0; i <= k; i ++) ans = (ans + Qpow(Mod - 1, k - i) * C(k, i) % Mod * i % Mod * Qpow(i - 1, n - 1)) % Mod;
	printf("%lld", ans);
	return 0;
}