CF1292C Xenon's Attack on the Gangs(dp)
思路:
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;
}
/*
**/