[NOIP2014]联合权值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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 }
以上是关于[NOIP2014]联合权值的主要内容,如果未能解决你的问题,请参考以下文章