题目链接
题目大意
给一颗 n n n个点的树,在这颗树的点上涂 k k k种颜色,要保证相邻的点的颜色不同,问:有多少种方案?
题目分析
一个性质:答案与树的形状无关。原因:相邻的点只需要选择与上一个点不一样的颜色就行了,不需要关心当前点具体选什么颜色。
所以,问题可以转化为对逐个点的分析:设 d p [ u ] [ c n t ] dp[u][cnt] dp[u][cnt]为前 u u u个点,选了 c n t cnt cnt种颜色的方案数。
对前 u u u个点,有 c n t cnt cnt种颜色,方案数来自前 u − 1 u-1 u−1个点的两个转移方向:
- 涂上新的颜色:前 u − 1 u-1 u−1个点已经有 c n t − 1 cnt-1 cnt−1种颜色,现在第 u u u个点可以选 k − ( c n t − 1 ) k-(cnt-1) k−(cnt−1)种新颜色
- 涂上旧的颜色:前 u − 1 u-1 u−1个点已经有 c n t cnt cnt种颜色,为了避免第 u u u个点和第 u − 1 u-1 u−1点颜色一样,所以第 u u u个点只能选 c n t − 1 cnt-1 cnt−1种旧颜色。
代码
#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
typedef long long LL;
int n, k;
LL dp[2505][2505];
int main() {
scanf("%d %d", &n, &k);
int t;
for(int i = 1; i <= n-1; i++) scanf("%d", &t);
dp[0][0] = 1;
for(int u = 1; u <= n; u++) { //u:当前点
for(int cnt = 1; cnt <= k; cnt++) { //cnt:用过的颜色数量
dp[u][cnt] += dp[u-1][cnt-1] * (k-(cnt-1)); //选新颜色
dp[u][cnt] += dp[u-1][cnt] * (cnt-1); //选旧颜色
dp[u][cnt] %= mod;
}
}
printf("%lld\n", dp[n][k]);
return 0;
}