[noip2014 d1t2] 联合权值

感觉自己越来越弱了...

题目链接

对于60%的数据,朴素枚举即可

对于100%的数据,考虑优化

我们注意到每条边的长度均为1,而要求点对距离为2,可见和同一个点有连边的两点之间就会产生权值

对于第一问,显然可以贪心保存最大和次大值从而避免n³的查询;

对于第二问,一个讲的清楚的-->链接

记sum为与一个结点相连的所有点的权值之和,则对于与之相连的每个点i,由结合律,它对答案的贡献就是w[i]*(sum-w[i])

抓住题目的特殊条件,从分析数据间的关系入手,便可有效地避免冗杂的运算,将时间复杂度降在O(k*n),k为较小的常数

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #define maxn 200200
 5 #define MOD 10007
 6 using namespace std;
 7 int n;
 8 int weight[maxn];
 9 vector<int> con[maxn];
10 int read(){
11     int x=0,f=1;
12     char ch=getchar();
13     while (ch<'0'||ch>'9'){
14         if (ch=='-') f=-1;
15         ch=getchar();
16     }
17     while (ch>='0'&&ch<='9'){
18         x=x*10+ch-'0';
19         ch=getchar();
20     }
21     return x*f;
22 }
23 int main(){
24     int ans1=0,ans2=0;
25     n=read();
26     for (int i=1;i<n;i++){
27         int u=read(),v=read();
28         con[u].push_back(v);
29         con[v].push_back(u);
30     }
31     memset(weight,0,sizeof(weight));
32     for (int i=1;i<=n;i++)
33       weight[i]=read();
34     for (int i=1;i<=n;i++){
35         int m1=0,m2=0,sum=0;
36         for (int j=0;j<con[i].size();j++){
37             if (weight[con[i][j]]>=m1){
38                 m2=m1;m1=weight[con[i][j]];
39             }
40             else if (weight[con[i][j]]>m2){
41                 m2=weight[con[i][j]];
42             }
43             sum+=weight[con[i][j]];
44         }
45         sum%=MOD;
46         ans1=max(ans1,m1*m2);
47         for (int j=0;j<con[i].size();j++){
48             ans2+=(weight[con[i][j]]*(sum-weight[con[i][j]]))%MOD;
49             ans2=(ans2+MOD)%MOD;
50         }
51     }
52     printf("%d %d\n",ans1,ans2);
53     return 0;
54 }
View Code

 黄学长树规的做法也值得借鉴

posted @ 2017-08-10 21:43  Vincent_hwh  阅读(151)  评论(0编辑  收藏  举报