• CF1292C Xenon's Attack on the Gangs(dp)


    di

    思路:

    Step1:

    首先考虑一下简化版本:如果是在一个链上,如何放置权值使得题意中求的和最大。
    (left[i])表示(i)左边的点数,(right[i])表示(i)右边的点数。
    1.最开始链上没有放置任何权值,(mex)为0,当前的答案为(0)
    2.第一步将权值(0)赋值给边((u,v)),这样(u)左边的任意一点跟(v)右边的任意一点构成的路径的答案都是(1),所以增加的权值为(right[v]*left[u])
    3.这一步将权值(1)赋值给下一条边,考虑怎么赋值使得增加的权值最大,贪心的考虑是将该权值与(0)挨着,这样(mex=2)的点的组合最多,组合的权值最大。
    后面的权值的赋值都类似于前两步,不过他们如何放置是最优的我们还不得而知,所以这可以使用动态规划来求全局最优。
    (dp[i][j])表示将区间([i,j])全部赋值得到的最大权值,
    转移过程中划分依据就是上一个区间是([i,j-1])还是([i+1,j])。两者增加的权值都是(right[j]*left[i])

    Step2:

    本题转移到了树上,由于点数只有(3000),可以将每条链都拿出来枚举一遍,复杂度是(O(n^{2}))
    首先处理出不同的根节点每个节点为根的每个子树的大小,也就是上面链过程的(left[i])(right[i]).同时处理出不同的根节点每个节点的父亲节点,为了(dp)转移的计算。
    然后,再枚举链的两个端点,进行记忆化搜索,就能得到答案了。

    参考

    代码:

    
    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include<map>
    #include<set>
    #include<vector>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<ll, ll>PLL;
    typedef pair<int, int>PII;
    typedef pair<double, double>PDD;
    #define I_int ll
    inline ll read()
    {
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')f = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    #define read read()
    #define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
    #define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i<(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    #define perr(i,a,b) for(int i=(a);i>(b);i--)
    ll ksm(ll a, ll b, ll p)
    {
        ll res = 1;
        while(b)
        {
            if(b & 1)res = res * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return res;
    }
    const int inf = 0x3f3f3f3f;
    #define PI acos(-1)
    const int maxn=3100;
    
    ll n;
    vector<ll>g[maxn];
    
    ll fa[maxn][maxn],siz[maxn][maxn],dp[maxn][maxn];
    
    void dfs(int root,int u,int f){
        siz[root][u]=1;
        for(int i=0;i<g[u].size();i++){
            int j=g[u][i];
    
            if(j==f) continue;
            fa[root][j]=u;
            dfs(root,j,u);
            siz[root][u]+=siz[root][j];
        }
    }
    
    ll DP(int x,int y){
        if(x==y) return 0;
        if(dp[x][y]) return dp[x][y];
        dp[x][y]=max(DP(x,fa[x][y]),DP(y,fa[y][x]))+siz[x][y]*siz[y][x];
        return dp[x][y];
    }
    
    int main()
    {
        n=read;
        rep(i,1,n-1){
            int u=read,v=read;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        rep(i,1,n) dfs(i,i,0);
        ll res=0;
        rep(i,1,n) rep(j,1,n) res=max(res,DP(i,j));
        printf("%lld
    ",res);
        return 0;
    }
    
    /*
    
    **/
    
    
    
    
    
  • 相关阅读:
    9月9号作业
    9月9号笔记
    jupyter的补充
    jupyter的使用
    9月6号作业
    编程语言的分类
    计算机组成
    计算机组成的补充
    面向对象基础
    9月2号作业
  • 原文地址:https://www.cnblogs.com/OvOq/p/14838795.html
Copyright © 2020-2023  润新知