20200407 树

题意转化

将一棵树剖分为若干个颜色不同的联通块,求数目。


题解

这种题目第一反应就是树形dp,但是由于涉及到联通块,所以应当和 dfs 序有一定的关系。

dfs 序可以将一个树形结构映射到一个序列上,从而实现一些操作。

树链剖分就是按照特定的顺序对树进行 dfs 序标定,之后通过如线段树之类的数据结构进行维护完成的。

此外,通过入栈出栈都记录的 dfs 序,可以实现求 LCA 。

代表在 dfs 序上前 个点,使用 种颜色染色的方案数。

考虑 有两种获得贡献的来源:

  • 一是和父亲涂一样的颜色
  • 二是自己新开一种颜色

得到方程如下:

边界是

答案为

Code

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

const int maxn = 300 + 7;
const int maxm = 600 + 7;
const int mod = 1000000007;

int n, k;
int Head[maxn], to[maxm], Next[maxm], tot;
LL dp[maxn][maxn];

void addedge(int x, int y) {
    to[++tot] = y, Next[tot] = Head[x], Head[x] = tot;
}
void add(int x, int y) {
    addedge(x, y);
    addedge(y, x);
}

template < typename Tp >
void read(Tp &x) {
    x = 0; int fh = 1; char ch = 1;
    while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if(ch == '-') fh = -1, ch = getchar();
    while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
    x *= fh;
}

void Init(void) {
    read(n); read(k);
    for(int i = 1, x, y; i < n; i++) {
        read(x); read(y);
        add(x, y);
    }
}

void Work(void) {
    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]*(k - j + 1))) % mod;
        }
    }
    LL ans = 0;
    for(int i = 1; i <= k; i++) ans = (ans + dp[n][i]) % mod;
    printf("%lld\n",ans);
}


int main(void) {
    Init();
    Work();
    return 0;
}