牛客网暑期ACM多校训练营(第三场) G-Coloring Tree 计数,思维题

Christmas is coming! Eddy has received a Christmas tree as gift. Not surprisingly, the tree consists of N vertices and N-1 edges and magically remains connected. Currently, all the vertex of the tree is uncolored. Eddy wants to color each vertex into one of K colors. However, there are too many way to color the tree(i.e. K N ways). Eddy doesn’t want the result of coloring being too boring. Thus, he defines the colorness of a tree as follow:

The colorness of a tree is the minimum distance between two vertex colored in the same color.

Now, Eddy is wondering how many way to color the tree such that the colorness of the tree will be D.

输入描述:

The first line of input contains three space-separated integer N, K, D indicating the number of vertices, number of colors, and the required colorness.
For each following N-1 lines, each contains two space-separated positive integer ui, vi indicating that there's an edge between ui and vi.

1 ≤ K < N ≤ 5000
1 ≤ D ≤ N
1 ≤ ui < vi ≤ N
It's guaranteed that the given input is a tree.

输出描述:

Output one line contains an integer indicating the number of way module 1000000007(109+7) to color the tree resulting in colorness being D.


输入例子:
2 1 1
1 2


输出例子:
1

题意:
给出一个n个节点的树,和k种染料。
定义一种染色方案的价值为树上相同颜色节点之间距离的最小值。
给出d 要求出价值为d的所有方案数

解题思路:
出题人讲解的很好。
对于这道题,求价值为d的方案数 有一种很直觉的做法。
就是 对于任意有没有可能在可接受时间内,求出价值大于d或者小于d的所有方案数的和。记做solve(d)
这样的话 我们的答案就是solve(d)-solve(d+1);
现在问题就转化成了求区间价值方案数的问题。
应该要想到的是,如果一种方案价值要大于等于d 那么对于每一个节点 它选择的颜色要和与它距离小于d的节点的颜色都不相同,那么这就是一个类似于全排列的问题。
然后就是一个我死也观察不出来的性质:

作者:xseventh
链接:https://www.nowcoder.com/discuss/88556?type=101&order=0&pos=2&page=0
如果我们按照bfs的顺序来选择颜色计算方案数的话,已经选过颜色的和当前节点距离在d以内的节点,一定两两距离都在d以内,就是说,当前节点距离d以内的已经选择过颜色的节点在选择颜色种类的时候一定会互相考虑到彼此节点,如果我们用dfs,就保证不了这个性质了。

接下来就很好写了

#include
#include
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int MAX=5e3+10;
const int MOD =  1e9+7;
int dis[MAX][MAX];
long long val[MAX];
int n,k,D;
int tot;
class Edge{
public:
    int v,next;
};
Edge edge[MAX<<2];
int head[MAX];
int vis[MAX];
void add(int u,int v){
    edge[tot].v=v;
    edge[tot].next=head[u];
    head[u] = tot;
    tot++;
}
void init(){
    tot=0;
    memset(head,-1,sizeof head);
}
void dfs(int s,int u,int pre){
    for(int i=head[u];i!=-1;i=edge[i].next){
        int v=edge[i].v;
        if(v==pre){
            continue;
        }
        dis[s][v]=dis[s][u]+1;
        dfs(s,v,u);
    }
}
int solve(int d){
    long long ans=1;
    memset(vis,0,sizeof vis);
    queue<int > Q;
    Q.push(1);
    for(int i=1;i<=n;i++){
        val[i]=k;
    }
    while(!Q.empty()){
        int now = Q.front();
        Q.pop();
        for(int i=1;i<=n;i++){
            if(vis[i] && dis[now][i]1;
        if(val[now]<=0) return 0;
        ans = (ans*val[now])%MOD;
        for(int i=head[now];i!=-1;i=edge[i].next){
            int v=edge[i].v;
            if(vis[v]) continue;
            Q.push(v);
        }
    }
    return ans;
}
int main(){
    init();
    scanf("%d %d %d",&n,&k,&D);
    for(int i=1;iint u,v;
        scanf("%d %d",&u,&v);
        add(u,v);
        add(v,u);
    }
    for(int i=1;i<=n;i++){
        dfs(i,i,0);
    }
//    for(int i=1;i<=n;i++){
//        for(int j=1;j<=n;j++){
//            cout<
//        }
//        puts("");
//    }
    cout<<(solve(D)-solve(D+1)+MOD)%MOD<

你可能感兴趣的:(脑洞,暴力求解)