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;
}

/*

**/




原文地址:https://www.cnblogs.com/OvOq/p/14838795.html