题目链接:点击这里
解题思路:
处理这个问题之前我们先来考虑更简单的问题:
在长度为n的连续块上有m种染色颜料,而且距离小于等于k的块颜色不能相同的染色数是多少?
首先我们知道如果m<k,那么肯定无解。
那么染色方案数为:m*(m-1)*(m-2)*(m-3)*...*(m-k+1)*(m-k+1)*(m-k+1)....
到第k块时它就会受到前面k-1块的限制,必须两两不同,所以他的可选择方案数就是(m-k+1)
那么回到现在的问题其实就是在树上解决这个问题,最后的答案就是距离大于等于d的方案数-距离大于等于d+1的方案数就是等于d的方案数了。
解决的关键就在于怎么找到两两受限的地方,那么我们通过广度搜索序(bfs)搜索就可以得到两两受限的数量,然后就可以得到该节点的可选方案数。
#include<bits/stdc++.h>
using namespace std;
const int mx = 5e3 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
int n,K,D,cnt[mx],top;
vector <int> vec[mx];
bool vis[mx];
void Order(int x,int d)
{
queue <int> que;
que.push(1);
vis[1] = 1;
while(!que.empty()){
int no = que.front();
que.pop();
cnt[top++] = no;
for(int v : vec[no]){
if(vis[v]) continue;
vis[v] = 1;
que.push(v);
}
}
}
int dfs(int x,int fa,int d)
{
if(d==D||!vis[x]) return 0;
int ret = 1;
for(int v : vec[x]){
if(v==fa) continue;
ret += dfs(v,x,d+1);
}
return ret;
}
ll solve()
{
memset(vis,0,sizeof(vis));
ll ans = 1;
for(int i=0;i<n;i++){
int v = cnt[i];
vis[v] = 1;
int k = K - dfs(v,0,0) + 1;
if(k<=0) return 0;//没有可选数
ans = ans*k%mod;
}
return ans;
}
int main()
{
scanf("%d%d%d",&n,&K,&D);
int a,b;
for(int i=1;i<n;i++){
scanf("%d%d",&a,&b);
vec[a].push_back(b);
vec[b].push_back(a);
}
Order(1,0);
ll ans1 = solve();
D++;
ll ans2 = solve();
printf("%lld\n",(ans1-ans2+mod)%mod);
return 0;
}