怎么每次写题解都打不开CF啊qwq
题意
给一棵n个点的树,给树边加0~n-1的权,权值不重复
求
∑
u
,
v
∈
V
,
u
≠
v
m
e
x
(
p
a
t
h
u
,
v
)
\sum_{u,v\in V,u\not=v}mex(path_{u,v})
u,v∈V,u=v∑mex(pathu,v)
的最大值
其中
p
a
t
h
u
,
v
path_{u,v}
pathu,v指以u,v为端点的路径上的边权组成的集合
思路
我首先考虑到了以下几点
(1)只有包含0的路径才对答案有贡献
(2)权值小的边就应该被包含于更多的路径中
本题的关键在于,每种可能的方案中一定存在一条路径,路径长为
l
l
l,恰好包含了0到l-1间的权值,并且使得
l
l
l最大
考虑到(2),我们发现,这条路径的最优情况一定是,路径的中间为0,向两侧递增的样子
于是使用dp去基于向短路径(比如l=k)两端中的一边加上权为k的边,来得到更长路径(l-k+1)的答案
然后就更新最大值就好了
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef complex<double> cp;
typedef pair<ll,ll> pll;
const int maxn=(int)3e3+9;
const int maxm=(int)1e6+9;
const ll mod=(ll)1e9+7;
const db pi=acos(-1);
const db eps=1e-15;
#define dbg(x) cerr<<#x<<" is "<<x<<endl;
vector<int> e[maxn];
ll f[maxn][maxn];
int n;
int fa[maxn][maxn];
int sz[maxn][maxn];
void init(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
a--,b--;
e[a].push_back(b);
e[b].push_back(a);
}
}
void dfs(int u,int f,int r){
fa[r][u]=f;
sz[r][u]=1;
for(int x:e[u]){
if(f==x)continue;
dfs(x,u,r);
sz[r][u]+=sz[r][x];
}
}
ll dp(int u,int v){
if(u==v)return 0;
if(f[u][v]>=0)return f[u][v];
int fu=fa[v][u];
int fv=fa[u][v];
f[u][v]=max(dp(fu,v),dp(u,fv))+sz[v][u]*sz[u][v];
f[v][u]=f[u][v];
return f[u][v];
}
int main(){
init();
memset(f,-1,sizeof(f));
for(int i=0;i<n;i++){
dfs(i,-1,i);
}
ll ans=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
ans=max(ans,dp(i,j));
}
}
printf("%lld\n",ans);
return 0;
}