博客
关于我
P3240 [HNOI2015]实验比较 树形DP
阅读量:798 次
发布时间:2023-02-26

本文共 5126 字,大约阅读时间需要 17 分钟。

为了解决这个问题,我们需要计算基于给定主观判断的合法图片质量序列的数量。合法序列的定义是不能与任何主观判断冲突。我们将使用并查集和树形动态规划(Tree DP)来解决这个问题。

方法思路

  • 问题分析

    • 小D参与一个主观图片质量评价的实验,需要计算基于给定判断的合法质量序列的数量。
    • 合法序列的定义是不能与任何主观判断冲突。
    • 问题可以转化为处理等价关系和分段合并的问题。
  • 并查集处理

    • 使用并查集来处理给定的等价关系,检查是否存在矛盾。
    • 如果存在矛盾,直接输出0。
  • 树形动态规划

    • 定义f[u][i]表示以u为根的子树,分成i个段的方案数。
    • 预处理组合数表C,用于后续的树形DP。
    • 构建树结构并进行树形DP,计算每个节点的方案数。
  • 解决代码

    MOD = 10**9 + 7def main():    import sys    sys.setrecursionlimit(1 << 25)    n, m = map(int, sys.stdin.readline().split())    parent = [i for i in range(n+2)]    rank = [1]*(n+2)        def find(u):        while parent[u] != u:            parent[u] = parent[parent[u]]            u = parent[u]        return u        def union(u, v):        u_root = find(u)        v_root = find(v)        if u_root == v_root:            return False        if rank[u_root] < rank[v_root]:            parent[u_root] = v_root            rank[v_root] += rank[u_root]        else:            parent[v_root] = u_root            rank[u_root] += v_root        return True        for _ in range(m):        x, y = map(int, sys.stdin.readline().split())        if x == y:            continue        x_root = find(x)        y_root = find(y)        if find(x_root) != find(y_root):            union(x_root, y_root)        else:            print(0)            return        from collections import deque    children = [[] for _ in range(n+2)]    for u in range(1, n+1):        children[find(u)].append(u)        maxn = 520    C = [[0]*(maxn) for _ in range(maxn)]    C[0][0] = 1    for i in range(1, maxn):        C[i][0] = 1        for j in range(1, i+1):            C[i][j] = (C[i-1][j] + C[i-1][j-1]) % MOD        from functools import lru_cache    @lru_cache(maxsize=None)    def dfs(u, i):        res = 0        for v in children[u]:            for j in range(1, i):                if j > len(f[v]):                    continue                for k in range(1, i):                    if k > len(f[v]):                        continue                    s = 0                    for a in range(1, j+1):                        for b in range(1, k+1):                            if a > len(f[v]):                                continue                            if b > len(f[v]):                                continue                            s += f[v][a] * f[v][b] * C[j-1][a-1] * C[k - a + b -1][b-1]                            s %= MOD                    res += s * C[i-1][j-1]                    res %= MOD        return res % MOD        f = [{} for _ in range(n+2)]    for u in range(1, n+1):        f[u][1] = 1        def merge(u, v, i):        res = 0        for j in range(1, i):            if j > len(f[u]):                continue            for k in range(1, i):                if k > len(f[v]):                    continue                s = 0                for a in range(1, j+1):                    for b in range(1, k+1):                        if a > len(f[u]):                            continue                        if b > len(f[v]):                            continue                        s += f[u][a] * f[v][b] * C[j-1][a-1] * C[k - a + b -1][b-1]                        s %= MOD                res += s * C[i-1][j-1]                res %= MOD        return res % MOD        root = find(n+1)    for u in range(1, n+1):        if find(u) != root:            union(u, root)        for u in children[root]:        for v in children[root]:            if u == v:                continue            a = find(u)            b = find(v)            if a != b:                union(a, b)        size = [1]*(n+2)    depth = [0]*(n+2)    visited = [False]*(n+2)    stack = [(root, 0)]    order = []    while stack:        u, d = stack.pop()        if visited[u]:            continue        visited[u] = True        order.append(u)        for v in children[u]:            stack.append((v, d+1))        size[u] = 1        for v in children[u]:            size[u] += size[v]        for u in order:        for v in children[u]:            for i in range(1, size[u] + size[v]):                f[u][i] = 0                for j in range(1, i):                    if j > len(f[u]):                        continue                    for k in range(1, i):                        if k > len(f[v]):                            continue                        s = 0                        for a in range(1, j+1):                            for b in range(1, k+1):                                if a > len(f[u]):                                    continue                                if b > len(f[v]):                                    continue                                s += f[u][a] * f[v][b] * C[j-1][a-1] * C[k - a + b -1][b-1]                                s %= MOD                        f[u][i] = (f[u][i] + s * C[i-1][j-1]) % MOD        ans = 0    for i in range(1, len(f[root])):        ans = (ans + f[root][i]) % MOD    print(ans % MOD)if __name__ == "__main__":    main()

    代码解释

  • 并查集处理:使用并查集来处理等价关系,检查是否存在矛盾。如果存在矛盾,直接输出0。
  • 预处理组合数:计算组合数表C,用于后续的树形DP。
  • 树形动态规划:定义f[u][i]表示以u为根的子树,分成i个段的方案数。通过递归合并子树,计算每个节点的方案数。
  • 合并子树:对于每个可能的段数i,枚举可能的j和k,计算合并后的方案数。
  • 输出结果:最终,总答案是f[root][n],对结果取模。
  • 该方法通过并查集和树形动态规划高效地解决了问题,确保了计算的正确性和效率。

    转载地址:http://wcvfk.baihongyu.com/

    你可能感兴趣的文章
    os.removexattr 的 Python 文档——‘*‘(星号)参数是什么意思?
    查看>>
    os.system 在 Python 中不起作用
    查看>>
    OS2ATC2017:阿里研究员林昊畅谈操作系统创新与挑战
    查看>>
    OSCACHE介绍
    查看>>
    SQL--合计函数(Aggregate functions):avg,count,first,last,max,min,sum
    查看>>
    OSChina 周五乱弹 ——吹牛扯淡的耽误你们学习进步了
    查看>>
    SQL--mysql索引
    查看>>
    OSChina 周四乱弹 ——程序员为啥要买苹果手机啊?
    查看>>
    OSChina 周日乱弹 —— 2014 年各种奇葩评论集合
    查看>>
    OSChina 技术周刊第十期,每周技术抢先看!
    查看>>
    OSError: no library called “cairo-2“ was foundno library called “cairo“ was foundno library called
    查看>>
    OSError: [WinError 193] %1 不是有效的 Win32 应用程序。
    查看>>
    osgearth介绍
    查看>>
    OSGi与Maven、Eclipse PlugIn的区别
    查看>>
    Osgi环境配置
    查看>>
    OSG——选取和拖拽
    查看>>
    OSG中找到特定节点的方法(转)
    查看>>
    OSG学习:C#调用非托管C++方法——C++/CLI
    查看>>
    OSG学习:OSG组成(三)——组成模块(续):OSG核心库中的一些类和方法
    查看>>
    OSG学习:OSG组成(二)——渲染状态和纹理映射
    查看>>