题目链接
Codeforces 1292C Xenon’s Attack on the Gangs
题目大意
给定一棵树,将 [ 0 , n − 2 ] [0,n-2] [0,n−2]内的每个整数都仅用一遍填到每条边上,使得 ∑ 1 ≤ u ≤ v ≤ n m e x ( u , v ) \sum_{1\leq u\leq v\leq n}mex(u,v) ∑1≤u≤v≤nmex(u,v)最大, m e x ( u , v ) mex(u,v) mex(u,v)表示从结点 u u u到结点 v v v经过的边集 A u , v A_{u,v} Au,v中未出现的最小非负整数。
解题思路
我们先来考虑样例,图是这样的:
那么,我们想一下边权为
0
0
0的这条边,它的贡献是多少,根据乘法原理,即
w
e
i
g
h
t
[
i
]
=
l
e
f
t
[
i
]
∗
r
i
g
h
t
[
i
]
,
weight[i]=left[i]*right[i],
weight[i]=left[i]∗right[i],
它的贡献就是左边的点数
×
×
×右边的点数,
3
×
2
=
6
3×2=6
3×2=6。左边是
(
1
,
2
,
4
)
(1,2,4)
(1,2,4),右边是
(
3
,
5
)
(3,5)
(3,5)。
接下去我们算一下边权为 1 1 1的边,但是单单一个边权为 1 1 1的边是做不出任何贡献的,因为有比 1 1 1更小的非负整数 0 0 0,所以这条边必须和边权为 0 0 0的边连在一起才能做出贡献,那么左边的点是 ( 1 , 2 , 4 ) (1,2,4) (1,2,4),右边的点是 ( 5 ) (5) (5),贡献是 3 × 1 = 3 3×1=3 3×1=3。
同理,边权为 2 2 2的边要和边权为 0 0 0的边,边权为 1 1 1的边组成一条链,所以左边的点是 ( 4 ) (4) (4),右边的点是 ( 5 ) (5) (5),贡献是 1 × 1 = 1 1×1=1 1×1=1。
但是边权为 3 3 3的边是做不出任何贡献的,因为这条边和边权为 0 , 1 , 2 0,1,2 0,1,2的边无法组成一条链,它包含不了 0 − 3 0-3 0−3的所有数。
所以样例的答案就是 6 + 3 + 1 = 10 6+3+1=10 6+3+1=10。
可能还有疑惑的地方,比如边权为 2 2 2的边和边权为 0 , 1 0,1 0,1的边连起来后每次贡献应该是最小非负整数 2 + 1 = 3 2+1=3 2+1=3,为什么每个的贡献都是 1 1 1呢?
因为我们在边权为 0 0 0的边的时候已经加了 1 1 1的贡献,那么边权为 1 1 1的边只是在原来的基础上叠加 2 2 2的贡献,边权为 2 2 2的这条边,只需在贡献 1 , 2 1,2 1,2的边上叠加一层 3 3 3的贡献。
所以我们的做法就是:在树上找所有的链再计算贡献。
C
o
d
e
Code
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=3005;
long long dp[maxn][maxn],cnt[maxn][maxn];
int fa[maxn][maxn],h[2*maxn],nxt[2*maxn],to[2*maxn],n,x,y,ct;
void dfs(int x,int f,int root){
cnt[root][x]=1;fa[root][x]=f;
for(int i=h[x];i;i=nxt[i]){
int v=to[i];
if(v==f)continue;
dfs(v,x,root);
cnt[root][x]+=cnt[root][v];
}
}
long long solve(int x,int y){
if(x==y)return 0;
if(dp[x][y]!=-1)return dp[x][y];
dp[x][y]=cnt[y][x]*cnt[x][y]+max(solve(fa[y][x],y),solve(x,fa[x][y]));
return dp[x][y];
}
int main(){
cin>>n;
for(int i=1;i<n;i++){
cin>>x>>y;x--,y--;
to[++ct]=y,nxt[ct]=h[x],h[x]=ct;
to[++ct]=x,nxt[ct]=h[y],h[y]=ct;
}
for(int i=0;i<n;i++)dfs(i,-1,i);
memset(dp,-1,sizeof(dp));
long long ans=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans=max(ans,solve(i,j));
cout<<ans<<endl;
}
这边有个视频讲得还不错,值得看看,bilibili。