CodeForces 855C Helga Hufflepuff‘s Cup 树形dp

CodeForces 855C Helga Hufflepuff's Cup 树形dp


传送门:

题意

给 一 棵 树 , 有 m 种 颜 色 1 − m , 其 中 x 种 是 特 殊 颜 色 , k 是 特 殊 颜 色 的 编 号 。 给一棵树,有m种颜色1-m,其中x种是特殊颜色,k是特殊颜色的编号。 m1mxk
问 如 何 给 树 涂 色 , 特 殊 颜 色 的 节 点 不 能 连 特 殊 颜 色 , 只 能 连 比 他 编 号 小 的 颜 色 。 问如何给树涂色,特殊颜色的节点不能连特殊颜色,只能连比他编号小的颜色。

问 , 能 有 多 少 种 涂 色 方 案 ? 问,能有多少种涂色方案?

思路

树 、 节 点 、 计 数 、 特 殊 情 况 − − 树 形 d p 。 树、节点、计数、特殊情况--树形dp。 dp

颜 色 数 量 高 达 1 e 9 , 而 特 殊 颜 色 数 量 只 有 10 , 所 以 我 们 围 绕 特 殊 颜 色 展 开 状 态 转 移 。 颜色数量高达1e9,而特殊颜色数量只有10,所以我们围绕特殊颜色展开状态转移。 1e910

因 为 特 殊 颜 色 的 连 接 是 有 要 求 的 , 所 以 可 以 分 成 三 类 。 因为特殊颜色的连接是有要求的,所以可以分成三类。

  • 0 表 示 特 殊 颜 色 0表示特殊颜色 0
  • 1 表 示 比 特 殊 颜 色 编 号 小 的 颜 色 1表示比特殊颜色编号小的颜色 1
  • 2 表 示 比 特 殊 颜 色 编 号 大 的 颜 色 2表示比特殊颜色编号大的颜色 2

所 以 设 f [ u ] [ i ] [ j ] 表 示 以 u 为 根 节 点 的 子 树 中 , i 个 特 殊 颜 色 , 当 前 点 颜 色 为 j 的 方 案 数 。 所以设f[u][i][j]表示以u为根节点的子树中,i个特殊颜色,当前点颜色为j的方案数。 f[u][i][j]uij

根 据 特 殊 颜 色 来 转 移 : 根据特殊颜色来转移:
f [ u ] [ i + j ] [ 0 ] + = f [ u ] [ i ] [ 0 ] ∗ f [ v ] [ j ] [ 1 ] f[u][i+j][0]+=f[u][i][0]*f[v][j][1] f[u][i+j][0]+=f[u][i][0]f[v][j][1]

f [ u ] [ i + j ] [ 1 ] + = f [ u ] [ i ] [ 1 ] ∗ ( f [ v ] [ j ] [ 0 ] + f [ v ] [ j ] [ 1 ] + f [ v ] [ j ] [ 2 ] ) f[u][i+j][1]+=f[u][i][1]*(f[v][j][0]+f[v][j][1]+f[v][j][2]) f[u][i+j][1]+=f[u][i][1](f[v][j][0]+f[v][j][1]+f[v][j][2])

f [ u ] [ i + j ] [ 2 ] + = f [ u ] [ i ] [ 2 ] ∗ ( f [ v ] [ j ] [ 1 ] + f [ v ] [ j ] [ 2 ] ) f[u][i+j][2]+=f[u][i][2]*(f[v][j][1]+f[v][j][2]) f[u][i+j][2]+=f[u][i][2](f[v][j][1]+f[v][j][2])

因 为 转 移 的 时 候 是 + = , 所 以 需 要 一 个 辅 助 函 数 来 帮 忙 存 储 , 防 止 新 产 生 的 值 对 后 续 转 移 产 生 影 响 。 因为转移的时候是+=,所以需要一个辅助函数来帮忙存储,防止新产生的值对后续转移产生影响。 +=,

Code

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

typedef long long ll;

const ll mod = 1e9 + 7;
const int N = 1e5 + 10;
int n, m, k, x;
vector<int> g[N];
ll dp[11][3], f[N][11][3]; // [以u为根的子树][i种特殊颜色][0/1/2,特殊颜色,小于特殊颜色,大于特殊颜色]
int siz[N];

void dfs(int u, int fa) {
    siz[u] = 1;
    f[u][1][0] = 1;
    f[u][0][1] = k - 1; // 小于特殊颜色的有k-1种
    f[u][0][2] = m - k; // 大于特殊颜色的有m-k种
    for(auto v : g[u]) {
        if(v == fa) continue;
        dfs(v, u);
        mem(dp, 0);
        siz[u] += siz[v];
        for(int i = 0;i <= min(siz[u], x); i++) {
            for(int j = 0;j <= siz[v] && i + j <= x; j++) {
                dp[i + j][0] = (dp[i + j][0] + f[u][i][0] * f[v][j][1] % mod) % mod;
                dp[i + j][1] = (dp[i + j][1] + f[u][i][1] * (f[v][j][0] + f[v][j][1] + f[v][j][2]) % mod) % mod;
                dp[i + j][2] = (dp[i + j][2] + f[u][i][2] * (f[v][j][1] + f[v][j][2]) % mod) % mod;
            }
        }
        for(int i = 0;i <= min(siz[u], x); i++) {
            for(int j = 0;j < 3; j++) {
                f[u][i][j] = dp[i][j];
            }
        }
    }
}

void solve() {
    scanf("%d%d",&n,&m);
    for(int i = 1;i < n; i++) {
        int u, v; scanf("%d%d",&u,&v);
        g[u].eb(v); g[v].eb(u);
    }
    scanf("%d%d",&k,&x);
    dfs(1, 0);
    ll ans = 0;
    for(int i = 0;i <= x; i++) {
        for(int j = 0;j < 3; j++) {
            ans = (ans + f[1][i][j]) % mod;
        }
    }
    printf("%lld\n",ans);
}

signed main() {
    solve();
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值