zoukankan      html  css  js  c++  java
  • BZOJ4033: [HAOI2015]T1

    Description

    有一棵点数为 N 的树,树边有边权。给你一个在 0~ N 之内的正整
    数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的
    N-K个点染成白色 。 将所有点染色后,你会获得黑点两两之间的距
    离加上白点两两之间的距离的和的受益。问受益最大值是多少。

    Input

     第一行包含两个整数 N, K 。

    接下来 N-1 行每行三个正整数 fr, to, dis , 表示该树中存在一条长度
    为 dis 的边 (fr, to) 。输入保证所有点之间是联通的。

    Output

    输出一个正整数,表示收益的最大值。

    Sample Input

    3 1
    1 2 1
    1 3 2

    Sample Output

    3

    HINT

    对于 100% 的数据, 0<=K<=N <=2000
     
     
    这是一道好题。。。
    设f[i][j]表示以i为根的子树选出j个黑点的最大收益,要费用提前计算。
    则考虑u的子节点v,在v的子树选k个,则f[u][j+k]=max(f[u][j]+f[v][k])+v子树中的黑点到外面的黑点距离+v子树中的白点到外面的白点距离
    后面的两个倒腾倒腾式子就行了。
    然后注意这样的代码是O(n^2)的而不是O(n^3)的。
    siz[x]=1;
    ren if(to[i]!=fa) {
        dp(to[i],x);
        rep(j,0,siz[x]) rep(k,0,siz[to[i]]) 
            update(f[x][j],f[to[i]][k]);
        siz[x]+=siz[to[i]];
    }
    View Code

    为什么呢?考虑那个二重循环,可以看做分别枚举两棵子树的每个点。你会发现,点对(u,v),只会在计算lca(u,v)的dp时才被考虑到,所以复杂度是O(n^2)。

    #include<cstdio>
    #include<cctype>
    #include<queue>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define dwn(i,s,t) for(int i=s;i>=t;i--)
    #define ren for(int i=first[x];i;i=next[i])
    using namespace std;
    const int BufferSize=1<<16;
    char buffer[BufferSize],*head,*tail;
    inline char Getchar() {
        if(head==tail) {
            int l=fread(buffer,1,BufferSize,stdin);
            tail=(head=buffer)+l;
        }
        return *head++;
    }
    inline int read() {
        int x=0,f=1;char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    typedef long long ll;
    const ll inf=1ll<<60;
    const int maxn=2010;
    int n,m,first[maxn],next[maxn<<1],to[maxn<<1],dis[maxn<<1],e;
    void AddEdge(int w,int v,int u) {
        to[++e]=v;dis[e]=w;next[e]=first[u];first[u]=e;
        to[++e]=u;dis[e]=w;next[e]=first[v];first[v]=e;
    }
    ll f[maxn][maxn],tmp[maxn],siz[maxn];
    void dp(int x,int fa) {
        siz[x]=1;
        ren if(to[i]!=fa) {
            dp(to[i],x);
            rep(j,0,siz[x]) rep(k,0,siz[to[i]]) 
                tmp[j+k]=max(tmp[j+k],f[x][j]+f[to[i]][k]+(ll)dis[i]*(k*(m-k)+(siz[to[i]]-k)*(n-m-siz[to[i]]+k)));
            siz[x]+=siz[to[i]];
            rep(j,0,siz[x]) f[x][j]=tmp[j],tmp[j]=-inf;
        }
    }
    int main() {
        n=read();m=read();
        rep(i,2,n) AddEdge(read(),read(),read());
        rep(i,1,n) rep(j,2,m) f[i][j]=-inf;
        rep(i,0,n) tmp[i]=-inf;
        dp(1,0);printf("%lld
    ",f[1][m]);
        return 0;
    }
    View Code
  • 相关阅读:
    4种方法帮你解决IntelliJ IDEA控制台中文乱码问题
    万字长文:解读区块链7类共识算法
    CoralCache:一个提高微服务可用性的中间件
    探究Python源码,终于弄懂了字符串驻留技术
    OAuth:每次授权暗中保护你的那个“MAN”
    厉害了!这群95后正在用三维成像技术让科幻变成现实
    华为云FusionInsight MRS在金融行业存算分离的实践
    【新春特辑】发压岁钱、看贺岁片、AI写春联……华为云社区给大家拜年了
    Java实现 蓝桥杯 算法训练 天数计算
    WebRTC框架中的硬件加速
  • 原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5013536.html
Copyright © 2011-2022 走看看