NOIP2014day1有个题目叫联合权值
题目描述
无向连通图 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 个用空格隔开的正整数 u、v,表示编号为 u 和编号为 v 的点 之间有边相连。
最后 1 行,包含 n 个正整数,每两个正整数之间用一个空格隔开,其中第 i 个整数表示 图 G 上编号为 i 的点的权值为Wi
。
输出格式
输出共 1 行,包含 2 个整数,之间用一个空格隔开,依次为图 G 上联合权值的最大值 和所有联合权值之和。由于所有联合权值之和可能很大,输出它时要对10007取余。
样例输入
5
1 2
2 3
3 4
4 5
1 5 2 3 10
样例输出
20 70
限制
对于 30%的数据,1 < n ≤ 100;
对于 60%的数据,1 < n ≤ 2000;
对于 100%的数据,1 < n ≤ 200,000,0 < Wi
≤ 10,000。
这么一道题,有一个很显而易见的做法,N^2枚举,当然,只能拿60分
题目上说n-1条边的无向连通图,实际上就是告诉我们这是一棵树,那么很显然是不存在环的
而距离为2的点,实际上就是与每个点直接存在边相连的任意两个不同点
那么很轻易可以想到要枚举中间点,然后对于它周围一圈的点进行计算
因为是树不存在环,所以可以确保计算不重复
最大值很轻易,就是周围一圈点中最大两个点的乘积取最大值
那么剩下就是求和的问题了
如果不考虑时间和空间,就是双重循环跑一趟就好了
然后可以发现,对于周围这一圈每个点都要与其他点相乘
那么对于每个点,设sum=周围一圈点的权值和,Wi
又因为是有序点对,(i,j)和(j,i)被认为不同
那么每个点对答案都有一个Wi*(sum-Wi)的贡献,那么只要跑一趟就可以了
复杂度是O(N)的,因为每条边最多两次被参与计算
代码在下面
const tt=10007; var link,a:array[0..200005]of longint; son,next:array[0..400005]of longint; n,tot,ans1,ans:longint; procedure add(x,y:longint); begin inc(tot);son[tot]:=y;next[tot]:=link[x];link[x]:=tot; end; procedure init; var x,y,i,j:longint; begin assign(input,'link.in');reset(input); assign(output,'link.out');rewrite(output); fillchar(link,sizeof(link),0); readln(n); tot:=0; for i:=1 to n-1 do begin readln(x,y); add(x,y);add(y,x); end; for i:=1 to n do read(a[i]); end; procedure main; var i,j,x,y,sum:longint; begin a[0]:=0; ans:=0;ans1:=0; for i:=1 to n do begin sum:=0;x:=0; j:=link[i]; while j<>0 do begin if a[son[j]]>a[x] then x:=son[j]; sum:=(sum+a[son[j]])mod tt; j:=next[j]; end; j:=link[i];y:=0; while j<>0 do begin if (a[son[j]]>a[y])and(son[j]<>x) then y:=son[j]; ans:=(ans+a[son[j]]*(sum+tt-a[son[j]]))mod tt; j:=next[j]; end; if a[x]*a[y]>ans1 then ans1:=a[x]*a[y]; end; end; procedure print; begin writeln(ans1,' ',ans); close(input);close(output); end; begin init; main; print; end.
还发生了小插曲
我写好后,测评只有20
和学长认认真真检查了一个晚上,发现取模错了,应该对10007,我写成了70007
然后好不服,因为百度文库点开的题目就是70007
最后,学长语重心长的说“听我的,撞墙吧,网上几千份,你刚好点开了错了”
QAQ尴尬
【写的有漏洞的,欢迎路过大神吐槽】
2016-11-01 13:37:00
Ending.