[NOIP2014]联合权值

描述

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

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

输入格式

输入文件名为link.in。

第一行包含1个整数n。

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

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

输入样例:

5

1 2

2 3

3 4

4 5

1 5 2 3 10

输出格式

输出文件名为link.out。

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

输出样例:

20 74

备注

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

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

对于100%的数据,1<n≤200,000,0<Wi ≤10,000。


分析

一开始用纯暴力方法过了7个点。后来看网上一些题解,又仔细看了一遍题目,大致明白方法了。

由于产生联合权值的两点最短距离为2,所以可以认为这两个两个点由一个中转点连接。那么直接保存每个点的邻点,在这些邻点里两两配对就可以了。但两两配对显然太慢,计算每一个中转点邻点的联合权值都要O(k2)的计算(k为邻点个数)。这样显然是不划算的。网上有介绍了利用加法结合律(没错加法结合律)的优化:预处理出每个点i的邻点的权值总和S[i],那么总联合权值和SUM=sum{ sum{W[V[i][j]] * (S[i] - W[V[i][j]])} (0≤j≤k) } (1≤i≤n)。

而最大权值可以在计算S[i]的时候直接找到i邻点中最大的两个相乘找到。

tyvj上可以直接AC,vijos需要用getint优化读入。

代码

 1 #include <cstdio>
 2 #include <cctype>
 3 #include <vector>
 4 using namespace std;
 5 vector<int> V[200001];
 6 int S[200001];
 7 int W[200001];
 8 int n, maxx, sum;
 9 int getint()
10 {
11     char c = getchar();
12     while (!isdigit(c))
13         c = getchar();
14     int x = 0;
15     while (isdigit(c)) {
16         x = x * 10 + c - ‘0‘;
17         c = getchar();
18     }
19     return x;
20 }
21 void add(int i)
22 {
23     for (int j = 0; j != V[i].size(); ++j)
24         sum = (sum + (S[i] - W[V[i][j]]) * W[V[i][j]]) % 10007;
25 }
26 int main()
27 {
28     n = getint();
29     for (int i = 0, a, b; i != n - 1; ++i) {
30         a = getint();
31         b = getint();
32         V[a].push_back(b);
33         V[b].push_back(a);
34     }
35     for (int i = 1; i <= n; ++i)
36         W[i] = getint();
37     for (int i = 1; i <= n; ++i) {
38         int max1, max2;
39         max1 = 0;
40         max2 = 0;
41         for (int j = 0; j != V[i].size(); ++j) {
42             S[i] += W[V[i][j]];
43             if (S[i] > 10007)
44                 S[i] -= 10007;
45             if (W[V[i][j]] > max1) {
46                 max2 = max1;
47                 max1 = W[V[i][j]];
48             }
49             else if (W[V[i][j]] == max1 || W[V[i][j]] > max2)
50                 max2 = W[V[i][j]];
51         }
52         if (max1 * max2 > maxx)
53             maxx = max1 * max2;
54     }
55     for (int i = 1; i <= n; ++i)
56         add(i);
57     printf("%d\40%d", maxx, sum % 10007);
58     return 0;
59 }
时间: 2024-10-13 01:03:23

[NOIP2014]联合权值的相关文章

NOIP2014联合权值——史上最强解析

[解题思路] (虽然说下面的话可能有点多,但鄙人还是希望各位能看完,对理解大有裨益) 总的来说,本体让求两个值,一个所有权值联合后的和,二是最大的联合权值,那好,我们暂且先来看看这最大的联合权值 所谓联合权值,就是两个距离为2的节点的全职的乘积,那怎么乘着最大呢?对一个点来说,最大的乘积自然就是和它相邻的两个权值最大的节点的权值的乘积, 至于求这两个最大值,我们完全可以在读入数据的时候顺便处理一下嘛,举手之劳而已!! 对于所有的联合权值之和,我们要求你还是要有一点数学基础的,但也不高,三年级就足

[NOIP2014]联合权值 题解

题目大意: 有一棵树,求距离为2的点权的乘积的和以及最大值. 思路: 枚举每一个点,则与其相邻的点互为距离为2的点.该部分的最大值为点权最大的两个点的积,和为点的权值和的平方减去每个点的平方,这样每条边都被跑了两次,所以复杂度为O(n). 用邻接表存储要开双倍数组(无向),当然像cyk大神一样直接跑边就不用考虑这个了. 代码: 邻接表: 1 #include<cstdio> 2 const int mo=10007,M=200008; 3 int cnt,x,y,n,i,ans,tot,w[M

noip2014联合权值

http://codevs.cn/problem/3728/ 我们要做的是计算距离为2的有序对权值之和及最大值,最大值好弄,但一一枚举是不可行的,因为n<=200000,我们可以预处理一下,每次读入边的时候我们把与当前顶点有边相连的所有点的权值中的最大值及次大值保存起来,然后用个O(n)时间就可以计算出来.至于权值和,我们可以这样,用s[i]存储与节点i相连的节点的权值和,枚举每条边(u,v),sigma((s[u]-w[v])*w[v]+(s[v]-w[u])*w[u])mod 1007 即是

【NOIP之旅】NOIP2014 day1 T2 联合权值

2.联合权值 (link.cpp/c/pas) [问题描述] 无向连通图G有n个点,n-1条边.点从1到n依次编号,编号为i的点的权值为Wi  ,每条边的长度均为1.图上两点(u, v)的距离定义为u点到v点的最短距离.对于图G上的点对(u, v),若它们的距离为2,则它们之间会产生Wu×Wv的联合权值. 请问图G上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? [输入] 输入文件名为link.in. 第一行包含1个整数n. 接下来n-1行,每行包含2个用空格隔开

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

题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu ×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式: 输入文件名为link .in. 第一行包含1 个整数n . 接下来n - 1 行,

NOIP2014提高组第二题联合权值

还是先看题吧: 试题描述  无向连通图 G 有 n 个点,n-1 条边.点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi ,每条边的长度均为 1.图上两点(u, v)的距离定义为 u 点到 v 点的最短距离.对于图 G 上的点对(u, v),若它们的距离为 2,则它们之间会产生Wu * Wv 的联合权值.请问图 G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入 第一行包含 1 个整数 n.接下来 n-1 行,每行包含 2 个用空格隔开的正整数 

Noip2014模拟赛解题心得【联合权值】

首先说明一下,我是一个刚刚进入oi界不到半年的蒟蒻--半年来,我是仅仅凭着兴趣和决心,在校队的一群dalao中瑟瑟发抖.我做的很多题目都是"苟"出来的,就比如说这次模拟赛中的"联合权值",仅凭暴力只坑了40分. 现在就从这道题目开始分析吧.题目如下: 标题: 联合权值 详情: 输入格式: 第一行包含 1 个整数 n. 接下来 n-1 行,每行包含 2 个用空格隔开的正整数 u.v,表示编号为 u 和编号为 v 的点 之间有边相连. 最后 1 行,包含 n 个正整数,

【学术篇】luogu1351 [NOIP2014提高组] 联合权值

一道提高组的题..... 传送门:题目在这里.... 现在都懒得更自己的blog了,怕是太颓废了_ (:з」∠) _ 好久没做题了,手都生了.(好吧其实是做题方面手太生了) 这题我都不想讲了,把代码一贴就算了呗.. 但还是要说说的.... 首先,题目里说:"无向连通图G 有n 个点,n - 1 条边." 我们可以知道这是一棵树(怕不是废话..),这样遍历的时候就能保证是O(n)级别了.. 找最大值 很简单,遍历树的时候找一下与每个点相连的点的最大值和次大值一乘就完了...显然这么贪心是

$Noip2014/Luogu1351$ 联合权值 树形

$Luogu$ $Description$ 给定一棵树,每两个距离为$2$的点之间可以产生"联合权值","联合权值"定义为这两个数的乘积.求最大的联合权值以及所有的联合权值之和.注意这两个数是有序的,翻译成人话就是求完和之后要$*2$. $Sol$ 想起了消防局的设立$ovo$. 距离为$2$的点,它们不是兄弟就是祖孙,那直接$dfs$一遍更新答案就好了叭. 兄弟之间更新答案这里有两个优化: 1.贪心.把所有的兄弟加入数组$s$之后按照$w[i]$从大到小排序,一遍