• 题解:「CEOI2017」Chase


    题面 Link

    为了方便,题面中的 (F_i) 在下面描述中改为 (P_i)(V) 改为 (m)

    子任务一: Brute Force

    直接枚举,时间复杂度 (mathcal{O}(n^2 2^n))

    子任务二 / 三: Greedy

    需要优化掉暴力枚举的 (2^n) ,考虑贡献法。

    通过简单手玩,若设 (S_u) 表示与节点 (u) 相邻的所有铁球和,发现每个节点对答案的贡献是 (S_u - F_{lst})(lst) 表示上一个走过节点的编号。

    这样记录每一条链上点所有的贡献,存在 std::set 中,到叶子节点取最大贡献并统计答案即可。

    时间复杂度 (mathcal{O}(n^2 mlog m))

    子任务四: DP

    不妨将一条链 (u ightarrow v) 看成 (u ightarrow p)(p ightarrow v)

    这样就可以通过枚举 (p) 并记录其子树信息的最优解来解决问题了。

    (F(u,i)) 表示用了 (leq i) 次磁铁,从以 (u) 为根的子树中一个节点到 (u) 的路径的贡献的最大值。

    (G(u,i)) 表示用了 (leq i) 次磁铁,从节点 (u) 到子树中一个节点的路径贡献的最大值。

    显然有转移方程:

    [F(u,i) = max{F(u,i - 1), F(v, i), F(v, i - 1) + S_u - P_v} ]

    [G(u,i) = max{G(u,i - 1), G(v, i), G(v, i - 1) + S_v - P_u} ]

    但是 (Ans eq max{F(u,i) + G(v,m - i) , G(u,i) + F(v,m - i)})

    所以对于一个节点,我们需要先记录已经遍历过的子树的最优信息,再与当前子树合并即可。

    时间复杂度 (mathcal{O}(n imes m))

    #include <bits/stdc++.h>
    #define forn(i,s,t) for(register int i=(s);i<=(t);++i)
    using namespace std;
    typedef long long LL;
    const int N = 1e5 + 3, M = 1e2 + 3;
    struct List {
        int dir, nxt;
    } E[N << 1];
    template<typename T>inline T Max(T A, T B) {
        return A > B ? A : B;
    }
    int T[N], cnt;
    inline void Add(int u, int v) {
        E[++cnt].dir = v, E[cnt].nxt = T[u], T[u] = cnt;
    }
    int n, m;
    LL P[N], val[N], F[N][M], G[N][M], Ans;
    LL Fsub[M], Gsub[M];
    // F:: Up Sta G:: Dn Sta
    void dfs(int u, int fa) {
        forn(i, 1, m) F[u][i] = val[u];
        Ans = Max(Ans, val[u]);
    
        for (register int i = T[u]; i; i = E[i].nxt) {
            int v = E[i].dir;
    
            if (v == fa)
                continue ;
    
            dfs(v, u);
            forn(j, 1, m) {
                Fsub[j] = Max(F[v][j], F[v][j - 1] + val[u] - P[v]);
                Gsub[j] = Max(G[v][j], G[v][j - 1] + val[v] - P[u]);
                Ans = Max(Ans, Max(Fsub[j] + G[u][m - j], Gsub[j] + F[u][m - j]));
            }
            forn(j, 1, m) {
                F[u][j] = Max(F[u][j], Max(F[u][j - 1], Fsub[j]));
                G[u][j] = Max(G[u][j], Max(G[u][j - 1], Gsub[j]));
            }
        }
    }
    int main() {
        scanf("%d%d", &n, &m);
    
        if (!m)
            return puts("0"), 0;
    
        forn(i, 1, n) scanf("%lld", P + i);
        forn(i, 2, n) {
            static int u, v;
            scanf("%d%d", &u, &v);
            Add(u, v), Add(v, u);
            val[v] += P[u], val[u] += P[v];
        }
        dfs(1, 0);
        printf("%lld
    ", Ans);
        return 0;
    }
    
  • 相关阅读:
    kafka+zookeeper集群部署
    rabbitmq集群部署
    nginx location语法
    rabbitmq单一部署
    Centos6国内可用yum源
    css
    imutable
    js解构复制语法
    redux
    json server问题
  • 原文地址:https://www.cnblogs.com/Ax-Dea/p/14493286.html
Copyright © 2020-2023  润新知