cf855 C. Helga Hufflepuff's Cup

题意:

在给定的一棵树上给节点染色。可以染m种颜色。定义一种特殊颜色mx,一棵树上最多能有mc个mx;如果一个节点为mx,那么他相邻的节点的值只能选比他小的颜色。问染色方案数。

\(n\le 1e5, 1\le m\le 1e9, 1\le mc \le 10\)

思路:

\(f(u,0/1/2,i)\) 表示 \(u\) 节点染 \([1,mx]/mx/[mx+1,m]\) ,以 \(u\) 为根的树中有 \(i\)\(mx\) 的方案数。答案为 \(\Sigma f(1,0\sim 2,0\sim mc)\)

每次树形dp都要解决这样一个问题:有 \(soncnt+1\) 堆石子,已知在每堆石子中选 \(0,1,2,\cdots mc\) 个的方案数,求一共选 \(0,1,2,\cdots mc\) 个的方案数。

这(大概)是个背包问题,枚举之前已经选的个数 \(i\),现在要从新的堆中选的个数 \(j\) 进行转移。要开个备份数组。

ll n, m, mx, mc, f[N][3][11], g[3][11];

void dfs(int u, int fa) {
    f[u][0][0] = mx - 1, f[u][1][1] = 1, f[u][2][0] = m - mx;

    for(int v : G[u]) if(v != fa) {
        dfs(v, u);

        memset(g, 0, sizeof g);

        for(int i = 0; i <= mc; i++)
        for(int j = 0; i + j <= mc; j++)
            add(g[0][i+j], f[u][0][i] * (f[v][0][j] + f[v][1][j] + f[v][2][j])),
            add(g[1][i+j], f[u][1][i] * f[v][0][j]),
            add(g[2][i+j], f[u][2][i] * (f[v][0][j] + f[v][2][j]));

        memcpy(f[u], g, sizeof g);
    }
}

signed main() {
    iofast;
    cin >> n >> m;
    for(int i = 1, a, b; i < n; i++)
        cin >> a >> b, G[a].pb(b), G[b].pb(a);
    cin >> mx >> mc;

    dfs(1, 0);

    int ans = 0;
    for(int i = 0; i < 3; i++)
        for(int j = 0; j <= mc; j++)
            (ans += f[1][i][j]) %= mod;
    cout << ans;
}

posted @ 2022-03-29 13:10  Bellala  阅读(67)  评论(0)    收藏  举报