题目描述

无向连通图 G 有 n 个点,n−1 条边。点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi​,每条边的长度均为 1。图上两点 (u,v) 的距离定义为 u 点到 v 点的最短距离。对于图 G 上的点对 (u,v),若它们的距离为 2,则它们之间会产生Wv​×Wu​ 的联合权值。

请问图 G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?

输入输出格式

输入格式:

第一行包含 1 个整数 n。

接下来 n−1 行,每行包含 2 个用空格隔开的正整数 u,v,表示编号为 u 和编号为 v 的点之间有边相连。

最后 1 行,包含 n 个正整数,每两个正整数之间用一个空格隔开,其中第 i 个整数表示图 G 上编号为 ii 的点的权值为 Wi​。

输出格式:

输出共 1 行,包含 2 个整数,之间用一个空格隔开,依次为图 G 上联合权值的最大值和所有联合权值之和。由于所有联合权值之和可能很大,输出它时要对10007取余。

输入输出样例

输入样例#1:

5
1 2
2 3
3 4
4 5
1 5 2 3 10
输出样例#1:

20 74

说明

本例输入的图如上所示,距离为2 的有序点对有(1,3) 、(2,4) 、(3,1) 、(3,5)、(4,2) 、(5,3)。

其联合权值分别为2 、15、2 、20、15、20。其中最大的是20,总和为74。

【数据说明】

对于30%的数据,1<n≤100;

对于60%的数据,1<n≤2000;

对于100%的数据,1<n≤200000,0<Wi​≤10000。

保证一定存在可产生联合权值的有序点对。

这题好难啊啊啊啊!相信我这是道好题!

解析:

先BB几句:

一开始暴力只得了70分。。。暴力思路我也说一下吧:

把联合权值分成两个部分,如果我们看到一个点,关于这个点的联合权值一种是爷爷×儿子,一种是儿子×儿子。

爷爷×儿子我拿个倍增做了,儿子×儿子我没办法了,想不出优化方法,只能爆搜一遍找两个儿子。复杂度大概是O(n^3),只得了70分。

就是这样:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#define N 200010
#define mod 10007
using namespace std;
queue<int> q;
int n,head[N],tot,w[N],f[N][],t,d[N];
struct rec{
int next,ver;
}g[N<<];
void add(int x,int y){
g[++tot].ver=y;
g[tot].next=head[x],head[x]=tot;
}
void reset(int x)
{
memset(d,,sizeof(d));
q.push(x);
d[x]=;
while(q.size())
{
int index=q.front();q.pop();
for(int i=head[index];i;i=g[i].next){
int y=g[i].ver;
if(d[y]) continue;
d[y]=d[x]+;
f[y][]=index;
for(int j=;j<=t;j++)
f[y][j]=f[f[y][j-]][j-];
q.push(y);
}
}
}
int main()
{
scanf("%d",&n);
t=(int)(log(n)/log()+);
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
for(int i=;i<=n;i++)
scanf("%d",&w[i]);
reset();
int ans=,cnt=;
for(int i=;i<=n;i++){
int tmp=w[i]*w[f[i][]];
ans=max(tmp,ans);
cnt=(cnt%mod+tmp%mod)%mod;
}
cnt<<=;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++){
if(i==j) continue;
if(f[i][]==f[j][]){
int tmp=w[i]*w[j];
ans=max(ans,tmp);
cnt=(cnt%mod+tmp%mod)%mod;
}
}
printf("%d %d\n",ans,cnt);
return ;
}

要AC正解的话,这道题似乎有三种解法。一种树形dp,一种dfs,一种非dfs。

某dalao跟我说的思路估计是dfs,但是我想到了非dfs。不过由于too yuong too simple,看了题解才后知后觉,我一直搞不清楚怎么去算它们的联合权值和。

主要在于这个乘法分配律啊,题解dalao居然用如此巧妙的方式解决了求权值和的问题。还有另一种方法需要一点数学技巧。

说说我的思路:

遍历一遍所有点,将所有与这个点相邻的点分别求权值和,累加到答案,得到权值和;

找到与这个点相邻的两个较大权值的点,求他们的联合权值(就是乘起来),更新最大值。

完事。

首先求最大的联合权值很简单。但是关键就在于我上面讲的,怎么求联合权值和这个问题上。

我一开始冥思苦想,怎么就是想不出怎么求某个点的3个相邻点之间所有的联合权值和,试了很多方法都不行。

至于为什么说3个相邻点,仔细想想,这是棵树,一个点最多连3条边。

看题解说乘法分配律?woc,真的没想到居然可以这样(也可以理解成加法结合律)。

也就是说,我们每次先求出这三个相邻点其中两个节点的联合权值,累加到答案中,再把它们两个的权值加起来,跟第三个相邻点相乘!这就相当于每个节点之间都乘了一次。

比如说这三个相邻节点是x,y,z,我们先求出x*y,再求出(x+y)*z,就相当于求出了x*z+y*z,但是注意,由于是我们只求出了单向的一次,所以最终答案要*2。

这种思路的AC代码(也是我的代码):

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#define N 200010
#define mod 10007
using namespace std;
int n,head[N],tot;
long long w[N];
struct rec{
int next,ver;
}g[N<<];
void add(int x,int y){
g[++tot].ver=y;
g[tot].next=head[x],head[x]=tot;
}
int main()
{
scanf("%d",&n);
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
for(int i=;i<=n;i++)
scanf("%lld",&w[i]);
long long ans=;
long long maxx=,t,mnow;
for(int i=;i<=n;i++){
int now=head[i];
t=(mnow=w[g[now].ver])%mod;
now=g[now].next;
for(;now;now=g[now].next){
int y=g[now].ver;
maxx=(maxx%mod+(t*w[y])%mod)%mod;
ans=max(mnow*w[y],ans);
mnow=max(mnow,w[y]);
t=(t%mod+w[y]%mod)%mod;
}
}
printf("%lld %lld\n",ans,(maxx<<)%mod);
return ;
}

还有一种思路,容我借张图。

给出dalao题解:戳这里

思路:

1、联合的两个节点距离为二,所以必定有一个中转点。所以,我们可以枚举每一个中转点。

2、假设每个中转点周围有两个点,权值分别为a、b,则联合权值为2ab=(a+b)^2-(a^2+b^2)。

3、若有三个点,权值分别为a、b、c,则联合权值为2ab+2bc+2ac=(a+b+c)^2-(a^2+b^2+c^2)。

4、综上,以某个节点为中转点的联合权值之和等于权值和的平方减去权值的平方和。

5、为了找到最大的联合权值,只需找到周围最大的两个权值max1,max2,相乘判断即可。

假设与某个点相邻的点为vi,我们有联合权值和:

这就是这个点可以求出的联合权值。

代码就不贴了,我又没写(逃

P1351 联合权值[鬼畜解法]的更多相关文章

  1. P1351 联合权值(树形dp)

    P1351 联合权值 想刷道水题还交了3次.....丢人 (1.没想到有两个点都是儿子的状况 2.到处乱%(大雾)) 先dfs一遍处理出父亲$fa[x]$ 蓝后再一遍dfs,搞搞就出来了. #incl ...

  2. 洛谷 P1351 联合权值 题解

    P1351 联合权值 题目描述 无向连通图 \(G\) 有 \(n\) 个点,\(n-1\) 条边.点从 \(1\) 到 \(n\) 依次编号,编号为 \(i\) 的点的权值为 \(W_i\)​,每条 ...

  3. [NOIP2014] 提高组 洛谷P1351 联合权值

    题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离. ...

  4. luogu P1351 联合权值

    题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离. ...

  5. 洛谷 P1351 联合权值

    题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离. ...

  6. 洛谷——P1351 联合权值

    https://www.luogu.org/problem/show?pid=1351 题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i , ...

  7. [NOIp2014] luogu P1351 联合权值

    哎我博 4 了. 题目描述 无向连通图 GGG 有 nnn 个点,n−1n−1n−1 条边.点从 111 到 nnn 依次编号,编号为 iii 的点的权值为 WiW_iWi​,每条边的长度均为 111 ...

  8. 『题解』洛谷P1351 联合权值

    更好的阅读体验 Portal Portal1: Luogu Portal2: LibreOJ Description 无向连通图\(\mathrm G\)有\(n\)个点,\(n - 1\)条边.点从 ...

  9. Luogu P1351 联合权值 题解

    这是一个不错的树形结构的题,由于本蒟蒻不会推什么神奇的公式其实是懒得推...,所以很愉快的发现其实只需要两个点之间的关系为祖父和儿子.或者是兄弟即可. 然后问题就变得很简单了,只需要做一个正常的DFS ...

随机推荐

  1. ubuntu下把python脚本转为二进制字节码文件

    ubuntu下把python脚本转为二进制字节码文件 听语音 原创 | 浏览:354 | 更新:2017-12-22 14:48 1 2 3 4 5 6 7 分步阅读 自己拥有个几个python脚本文 ...

  2. Ehcache配置文件ehcache.xml

    <?xml version="1.0" encoding="UTF-8"?> <ehcache xmlns:xsi="http:// ...

  3. LeetCode 14. 最长公共前缀(Longest Common Prefix)

    14. 最长公共前缀 14. Longest Common Prefix 题目描述 编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". Lee ...

  4. Java串口通信 RXTX 解决过程

    背景介绍: 由于第一次用Java与硬件通信,网上查了许多资料,在这进行整理,便于以后学习.本人串口测试是USB串口设备连接电脑,在设备管理器中找到端口名称(也可以通过一些虚拟串口工具模拟). 下面主要 ...

  5. Word 查找替换高级玩法系列之 -- 通配符大全A篇

    1. 通配符大全一览 序号 特殊字符(不使用通配符) 代码(不使用通配符) 特殊字符(使用通配符) 代码(使用通配符) 1 任意单个字符 ^? 任意单个字符 ? 2 任意数字 ^### 任意数字(单个 ...

  6. luoguP1823 [COI2007] Patrik 音乐会的等待

    题目描述 N个人正在排队进入一个音乐会.人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人.队列中任意两个人A和B,如果他们是相邻或他们之间没有人比A或B高,那么他们是可以互相看得见的. ...

  7. C之指针加减运算

    法则:1.指针减指针,语法正确,结果得一个整型值,表示两数值之间的对象类型的空间距离,而不是对象之间的字节数差值 2.指针加指针,语法错误,     3.指针加整形值,语法正确,表示后移N个空间单位 ...

  8. stm32之中断响应优先级

    1)中断响应分为:自然优先级.抢占优先级.响应优先级. 2)抢占优先级和响应优先级,其实是一个中断所包含的两个优先级,其中前者是抢占优先级之间的级别划分,后者是相同抢占优先级的优先级别的划分. 中断A ...

  9. 利用Python进行数据分析 第5章 pandas入门(1)

    pandas库,含有使数据清洗和分析工作变得更快更简单的数据结构和操作工具.pandas是基于NumPy数组构建. pandas常结合数值计算工具NumPy和SciPy.分析库statsmodels和 ...

  10. 数据结构-单链表-类定义C++

    原理可访问https://www.cnblogs.com/yang901112/p/11674333.html 头文件 #ifndef RLIST_H #define RLIST_H #include ...