• HAOI2015 树上染色


    一棵带边权的树,你需要把 $k$ 个点染成黑色,剩下的染成白色,你会获得黑点间两两间距离之和 + 白点间两两距离之和的收益

    求收益最大值

    $n leq 5000$

    sol:

    树形 dp

    显然一条边的贡献是 $边权 imes (左边白色 imes 右边白色 + 左边黑色 imes 右边黑色)$

    $f_{(x,i)}$ 表示 $x$ 子树内选了 $i$ 个黑点,子树里的边对全局答案的贡献

    然后我们按树上背包转移,转移的时候加的贡献其实是一条父子边的贡献

    我们假设在 $v$ 点下面放了 $w$ 个黑点

    这条边的贡献就是 $$边权 imes (w imes (k - w) + (size_v - k) imes (n - size_v - k + w))$$

    还是很简单的

    #include<bits/stdc++.h>
    #define LL long long
    #define int long long
    using namespace std;
    inline int read()
    {
        int x = 0,f = 1;char ch = getchar();
        for(;!isdigit(ch);ch = getchar())if(ch == '-')f = -f;
        for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0';
        return x * f;
    }
    const int inf = 1e16;
    int n,m,nk;
    struct EDG{int to,val;};
    vector<EDG> G[2100];
    int f[2100][2100],size[2100],tmp[2100];
    inline void dfs(int x,int fa)
    {
        size[x] = 1;
        for(int i=0;i<G[x].size();i++)
        {
            int to = G[x][i].to,len = G[x][i].val;
            if(to == fa)continue;
            dfs(to,x);
            fill(tmp,tmp+size[x]+size[to]+1,-inf);
            for (int j=0;j<=size[x];j++)
                for (int k=0;k<=size[to];k++)
                    tmp[j+k]=max(tmp[j+k],f[x][j]+f[to][k]+(LL)len*((LL)k*(m-k)+(LL)(n-size[to]-m+k)*(size[to]-k)));
            size[x]+=size[to];
            for (int j=0;j<=size[x];j++) f[x][j]=tmp[j];
        }
    }
    signed main()
    {
        n = read();m = read();
        nk = n - m;
        for(int i=2;i<=n;i++)
        {
            int u = read(),v = read(),w = read();
            G[u].push_back((EDG){v,w});
            G[v].push_back((EDG){u,w});
        }
        dfs(1,1);
        cout<<f[1][m];
    }
    View Code
  • 相关阅读:
    animation循环滚动
    <canvas>简单学习
    月末总结
    回顾-总结(2)
    初识正则
    学习中小项目遇到事
    在炎热的夏天学习以提高效率
    前端存储之cookie、localStorage
    总结(1)
    jQuery
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/9891088.html
Copyright © 2020-2023  润新知