题目描述
shy有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数。
输入描述:
第一行两个整数n,k代表点数和颜色数;
接下来n-1行,每行两个整数x,y表示x与y之间存在一条边;
输出描述:
输出一个整数表示方案数(mod 1e9+7)。
看上去是树形dp;
这题要是没想到把树上问题转化为dfs序是很难做的出来的;
转化为dfs序,就是一道线性dp,dp[i][j]表示前 i 个结点用 j 种颜色涂有多少种涂法;
那么转移方程为:dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(k-j+1);
分别表示在第 i 个点取一个已经出现过的颜色,在第 i 点取个新颜色(前面 i-1 个点没出现过);
为啥取一个已经出现过的颜色是 dp[i-1][j] ,因为如果第 i 个点涂的色在前 i-1 个结点中就已经出现过,第 i 个点必须和它父亲结点颜色相同;
看到这里,发现dfs序已经不重要了,什么树都是这样的;
代码:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=1100;
const int M=50100;
const LL mod=1e9+7;
int n,k;
LL dp[N][N];
int main(){
cin>>n>>k;
for(int i=1;i<n;i++){
int x,y;cin>>x>>y;
}
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=k;j++){
dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(1ll*(k-j+1));
dp[i][j]%=mod;
}
}
LL ans=0;
for(int i=1;i<=k;i++) (ans+=dp[n][i])%=mod;
cout<<ans<<endl;
return 0;
}