码迷,mamicode.com
首页 > 其他好文 > 详细

C. Helga Hufflepuff's Cup 树形dp 难

时间:2019-08-24 22:41:50      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:scan   tin   div   lap   它的   ++   algo   mes   type   

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 难

标签:scan   tin   div   lap   它的   ++   algo   mes   type   

原文地址:https://www.cnblogs.com/EchoZQN/p/11406265.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!