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\n",res);
    return 0;
}

/*

**/




posted @ 2021-06-01 20:40  OvO1  阅读(41)  评论(0编辑  收藏  举报