C. Helga Hufflepuff's Cup 树形dp 难

Posted echozqn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C. Helga Hufflepuff's Cup 树形dp 难相关的知识,希望对你有一定的参考价值。

C. Helga Hufflepuff‘s Cup

这个题目我感觉挺难的,想了好久也写了很久,还是没有写出来。

dp[i][j][k] 代表以 为根的子树中共选择了 j 个特殊颜色,且当前节点 i 的状态为 k 的染色方案数。

  1. k=0 ,代表当前节点 i 的颜色值小于 K 。
  2. k=1,代表当前节点 i 的颜色值等于 K 。
  3. k=2,代表当前节点 i 的颜色值大于 K 。

 

但是这个dfs过程的处理我觉得很复杂。

我们需要一个数组来进行临时的存储。

tmp[i][k] 表示选了 i 个  状态为 j 的方案数。

先枚举这个点已经用了 i 个,然后枚举这个子节点可以加上 j 个

tmp[j + h][0] += dp[u][j][0] * (dp[v][h][0] + dp[v][h][1] + dp[v][h][2]) % mod;
tmp[j + h][0] %= mod;
tmp[j + h][1] += dp[u][j][1] * dp[v][h][0] % mod;
tmp[j + h][1] %= mod;
tmp[j + h][2] += dp[u][j][2] * (dp[v][h][0] + dp[v][h][2]) % mod;
tmp[j + h][2] %= mod;

然后每次再赋值回去,注意这个tmp的定义,tmp[i,j]是k有 i 个,状态为 j 的方案。 

这个地方我觉得挺难想的,我是没有想到。

这个是对于每一个节点u,我们枚举它的子树,一开始这个dp[u] 的初始化要注意,

我们先考虑如果子树没有k,这个状态是怎么样的,因为只有这个状态我们是可以定下来的,如果有k,这种状态必须通过转移得来。

然后再枚举子树k的个数,再去更新这个节点u。

这里用了一点点的乘法原理,挺厉害的,我一开始想的是,枚举这个u的所有可能的k的数量,然后再去用背包,这个好像有点不对。

因为我们不是取最大的那个,而是取求组合数,应该枚举每一种可能,然后相乘,也有可能是我想的不太对。

 

技术图片
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <iostream>
#include <string>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 2e5 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
struct node 
    int v, nxt;
    node(int v = 0, int nxt = 0) :v(v), nxt(nxt) 
ex[maxn];
int head[maxn], cnt = 0;
int n, m, k, x;
void init()

    memset(head, -1, sizeof(head));
    cnt = 0;

void add(int u,int v)

    ex[cnt] = node(v, head[u]);
    head[u] = cnt++;
    ex[cnt] = node(u, head[v]);
    head[v] = cnt++;

int num[maxn];
ll tmp[20][3];
ll dp[maxn][20][3];//注意这个dp的定义,dp[i,j,x]表示到i这个节点,子树用k的数量为j,x==0 表示这个节点小于k,1代表等于k,2代表大于k
void dfs(int u,int pre)

    dp[u][0][0] = k - 1;
    dp[u][1][1] = 1;
    dp[u][0][2] = m - k;
    num[u] = 1;
    for (int i = head[u]; i != -1; i = ex[i].nxt) 
        int v = ex[i].v;
        if (v == pre) continue;
        dfs(v, u);
        memset(tmp, 0, sizeof(tmp));
        for (int j = 0; j <= num[u]; j++) 
            for (int h = 0; h <= num[v]; h++) 
                if (j + h > x) continue;
                tmp[j + h][0] += dp[u][j][0] * (dp[v][h][0] + dp[v][h][1] + dp[v][h][2]) % mod;
                tmp[j + h][0] %= mod;
                tmp[j + h][1] += dp[u][j][1] * dp[v][h][0] % mod;
                tmp[j + h][1] %= mod;
                tmp[j + h][2] += dp[u][j][2] * (dp[v][h][0] + dp[v][h][2]) % mod;
                tmp[j + h][2] %= mod;
            
        
        num[u] = min(x, num[u] + num[v]);
        for (int j = 0; j <= num[u]; j++) 
            for (int h = 0; h < 3; h++) 
                dp[u][j][h] = tmp[j][h];
            
        
    


int main()

    init();
    scanf("%d%d", &n, &m);
    for(int i=1;i<=n-1;i++)
    
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v);
    
    ll ans = 0;
    scanf("%d%d", &k, &x);
    dfs(1, -1);
    for (int i = 0; i <= x; i++) 
        for (int j = 0; j < 3; j++) 
            ans = (ans + dp[1][i][j]) % mod;
        
    
    printf("%lld\n", ans);
    return 0;
View Code

 

以上是关于C. Helga Hufflepuff's Cup 树形dp 难的主要内容,如果未能解决你的问题,请参考以下文章

Helga Hufflepuff's Cup CodeForces - 855C

855C Helga Hufflepuff's Cup

Codeforces 855C. Helga Hufflepuff's Cup----树形DP

C. Hexadecimal's Numbers

Codeforce Div-2 985 C. Liebig's Barrels

#614 C. NEKO's Maze Game