联合权值 vijos 1906 NOIP2014 D1T2 图结构

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

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

本题O(N2)枚举可以拿60分,注意到有序点对中(a,b)和(b,a)是一样的,并以此优化(只算 a<b 的情况,最终的和乘以2,最大值不受影响),可以拿70分。

正解需要推一下公式。

因为本题是n个点、n-1条边,所以一定是一棵树。对于一个点N及其所连的两个不同点A、B,可以知道DAB=DAN+DNB=2;即对于一个点,设其相邻的点构成集合E,那么集合E中的任意点两两组合出来的点对(A,B),一定有AB最短路是2,符合题目要求,可以计算联合权值。

我们设A、B、C三个点与D相连,权值分别为a、b、c,那么他们贡献的联合权值为  (ab+bc+ac)*2

眼熟么?想一想(a+b+c)2=a2+b2+c2+2ab+2bc+2ac,那么上式等价:(a+b+c)2-(a2+b2+c2

那么我们枚举每一个点,拿到其所相邻的点的平方和,即可求出这个点的所有相邻点贡献的全部联合权值(和的平方减去平方和)。

注意,中间过程的数比较大,可能需要开long long来运算。

这个是和的解法。那么最大值呢?

我们在计算的时候,取点N的相邻点中最大的权值w1、w2,那么点N的相邻点能形成的最大联合权值一定是w1*w2,我们以此更新答案即可。

附上AC代码

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cmath>
 5 #include<queue>
 6 #include<iostream>
 7 using namespace std;
 8 template<class T> inline void read(T &_a){
 9     bool f=0;int _ch=getchar();_a=0;
10     while(_ch<'0' || _ch>'9'){if(_ch=='-')f=1;_ch=getchar();}
11     while(_ch>='0' && _ch<='9'){_a=(_a<<1)+(_a<<3)+_ch-'0';_ch=getchar();}
12     if(f)_a=-_a;
13 }
14 
15 const int maxn=1200001,modx=10007;
16 struct edge
17 {
18     int to,next;
19 }e[maxn<<1];
20 long long n,egcnt,head[maxn],w[maxn],maxx,sum;
21 
22 inline void addedge(int from,int to)
23 {
24     e[++egcnt].to=to;
25     e[egcnt].next=head[from];
26     head[from]=egcnt;
27     e[++egcnt].to=from;
28     e[egcnt].next=head[to];
29     head[to]=egcnt;
30 }
31 
32 int main()
33 {
34     read(n);
35     for (register int i=1,a,b;i<n;++i) read(a),read(b),addedge(a,b);
36     for (register int i=1;i<=n;++i) read(w[i]);
37     for (register int i=1;i<=n;++i)
38     {
39         long long cnt1=0,cnt2=0,maxx1=0,maxx2=0;
40         for (register int v=head[i];v;v=e[v].next)
41         {
42             cnt1+=w[e[v].to];
43             cnt2+=w[e[v].to]*w[e[v].to];
44             cnt1%=modx;
45             cnt2%=modx;
46             if(w[e[v].to]>maxx1) maxx2=maxx1,maxx1=w[e[v].to];
47              else if (w[e[v].to]>maxx2) maxx2=w[e[v].to];
48         }
49         sum+=(cnt1*cnt1%modx-cnt2+modx)%modx;
50         sum%=modx;
51         maxx=max(maxx,maxx1*maxx2);
52     }
53     printf("%lld %lld",maxx,sum%modx);
54     return 0;
55 }
View Code
原文地址:https://www.cnblogs.com/jaywang/p/7742145.html