题意很明确了,大意就是一棵树,染色,距离 $\le 2$ 不得染同色,问染色方案。

首先我们要明确,距离 $\le 2$,具体是什么情况呢?

显然,分两个大类:

  • 一条链往下

    • 某节点和它的儿子
    • 某节点和它的孙子
  • 非一条链往下

    • 某节点和它的兄弟

那么我们就梳理出了 $3$ 中不能涂同一种颜色的情况。

读到这里,我想应该正解慢慢出来了。

其次我们要知道,总染色方案就是每个点染色方案之积。

那么每个点最初有 $k$ 种选择,我们看一下它是否存在爷爷,若存在最多只有 $k-2$ 种,因为有爷爷必然有爸爸。

一条链往下的方案已经考虑完了,接下来考虑兄弟。

兄弟就很简单了,记一个变量,自己的父亲每往下搜索一次加一,既能得到兄弟的个数。

详情见代码。

代码

#include<bits/stdc++.h>
using namespace std;
const int p=1000000007;
int n,k,u,v;
long long ans=1;//十年OI一场空,不开long long见祖宗
bool vis[100020];
vector<int>a[100020];
void dfs(int u,int tmp)//u表示目前节点 tmp表示当前节点涂色数量
{
    ans*=tmp;//乘上方案数
    ans%=p;//十年OI一场空,忘记取模见祖宗
    vis[u]=1;//遍历基本操作,也可以记录father
    int cnt=0;
    for(auto v:a[u])
    {
        if(vis[v])continue;
        int w=(u==1?k-1:k-2);//如果是自己根,自己的儿子没有爷爷,反之肯定有爷爷
        //上一条语句也可以写成dfs多带个dep参数,记录深度
        w-=cnt;//去除自己的兄弟所要染色的情况
        dfs(v,w);//继续搜索
        cnt++;//兄弟+1
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&u,&v);
        a[u].push_back(v);
        a[v].push_back(u);
        //建边基本操作,也可以单向
    }
    dfs(1,k);//开始搜索
    printf("%d\n",(int)ans);
    return 0;
}

最后修改:2023 年 04 月 23 日
v我50吃疯狂星期四