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