Codeforces 1292C Xenon's Attack on the Gangs

题目要求在树形结构中分配边的权重,目标是最大化路径上mex值的总和。通过分析样例,得出结论:边的权重应与相邻边形成链以增加贡献。解决方案是寻找树上的所有链并计算它们的贡献。
摘要由CSDN通过智能技术生成

题目链接

Codeforces 1292C Xenon’s Attack on the Gangs

题目大意

给定一棵树,将 [ 0 , n − 2 ] [0,n-2] [0,n2]内的每个整数都仅用一遍填到每条边上,使得 ∑ 1 ≤ u ≤ v ≤ n m e x ( u , v ) \sum_{1\leq u\leq v\leq n}mex(u,v) 1uvnmex(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 03的所有数。

所以样例的答案就是 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

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前台: (1)注册登录模块:按照学校的相关规定进行注册和登录。 (2)招聘信息查看:高校毕业生们可以网站首页上查看所有的招聘信息,除此之外还可以输入公司名称或岗位名称进行搜索。 (3)用人单位模块:此模块为宣传用人单位的主要功能模块,具体包括用人单位简介、岗位需求及职责及公司介绍等功能。 (4)就业指导:学生朋友们在就业前可以通过此模块获取指导。 (5)新闻信息:为了让用户们可以了解到最新的新闻动态,本系统可以通过新闻信息查看功能阅读近期的新闻动态。 (6)在线论坛:毕业季的同学们可以通过此模块相互交流。 后台: (1)系统用户管理模块:可以查看系统内的管理员信息并进行维护。 (2)学生管理模块:通过此功能可以添加学生用户,还可以对学生信息进行修改和删除。 (3)用人单位管理模块:管理员用户通过此模块可以管理用人单位的信息,还可以对用人单位信息进行查看和维护。 (4)招聘管理模块:管理员通过此功能发布和维护系统内的照片信息。 (5)就业指导管理模块:通过此模块可以编辑和发布就业指导信息,从而更好的帮助就业季的同学们。 (6)论坛管理:通过论坛管理可以查看论坛中的主题帖及里面的回复信息,除此之外还可以对论坛中的信息进行维护和管理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值