牛客每日一題 4.7 樹 樹dp+組合數學

昨天的牛客鴿了,我不會數學

首先第一步要理解題意就是要把樹分成多個聯通塊,每個聯通塊的顏色都要不一樣,求方案數。
爲什麼每個聯通塊的顏色都不一樣,因爲如果有同樣的顏色在不同的聯通塊上的話就無法滿足題意,這兩個點之間的路徑的所有點就不會是都是同一種色。

用f[i][j]代表的是以i爲根的子樹分成j個聯通塊的的方案數。由於我沒想到大佬說的分成j個聯通塊就是刪掉j-1條邊,所以就硬算去合併每個子樹的答案。
暴力合併就複雜度變成n^3;

得到每種聯通塊的方案數後就是組合數學算一下就好了,有j個聯通塊,就是在k種色裏選j個,然後在全排列

vector<int>xian[max_];
int f[max_][max_],n,k,cal[2][max_];
void dfs(int now, int fa) {
	for (auto to : xian[now]) {
		if (to == fa)continue;
		dfs(to, now);
	}
	memset(cal, 0, sizeof(cal));
	int last = 1;
	cal[0][1] = 1;
	for (auto to : xian[now]) {
		if (to == fa)continue;
		memset(cal[last], 0, sizeof(cal[last]));
		for (int i = 1; i <= k; i++) {
			for (int j = 1; j <= k; j++) {
				cal[last][i + j] += cal[last ^ 1][i] * f[to][j]; cal[last][i + j] %= mod;
				cal[last][i + j - 1] += cal[last ^ 1][i] * f[to][j]; cal[last][i + j - 1] %= mod;
			}
		}
		last ^= 1;
	}
	for (int i = 1; i <= k; i++) {
		f[now][i] = cal[last ^ 1][i];
	}
}
int value[max_];
signed main() {
	n = read(), k = read();
	for (int i = 2; i <= n; i++) {
		int a = read(), b = read();
		xian[a].push_back(b);
		xian[b].push_back(a);
	}
	dfs(1, 0);
	/*for (int i = 1; i <= k; i++) {
		cout << f[1][i] << endl;
	}*/
	value[1] = k;
	for (int i = 1; i <= 300; i++) {
		value[i + 1] = value[i] * (k - i);
		value[i + 1] %= mod;
	}
	int ans = 0;
	for (int i = 1; i <= k; i++) {
		ans += f[1][i] * value[i];
		ans %= mod;
	}
	//cout << endl;
	cout << ans;
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章