NOIP之旅:NOIP2014篇

A. 联合权值

标签:思维题,图论

该题浑身上下都是坑  果然还是我太弱了。

首先看题看的一脸懵逼,然后根据数据(n个点 n-1条边)我们知道其实这就是棵树嘛qwq

任务目标:求出最大联合权值,求所有联合权值之和。

主流题解有两条路:思维+技巧,树形DP

思维+技巧:首先构建基本模型。以一个点为中心,与其直接相邻的点互相为可联合的点,因为显然它们与该点距离为1,根据树的性质它们彼此之间的路径必定经过该点,即相互距离为2。 那么枚举每个点的每条边进行结算。对于任务目标2,我们可以看样例得出某些.... ...目标为a*b+b*c+......b*a+c*b. 经过简单的思考,继续套用上文模型,定义s[o]为指定点邻点的权值之和,定义ABCDEFG等一干字母为邻点,那么对于该点答案为 val[A]*(s[o]-val[A]) + ...

顺便吐槽某些题解:这是乘法分配律,不是什么加法结合律

 1 #include<cstdio>
 2 #include<iostream>
 3 #define maxn 500000
 4 using namespace std;
 5 
 6 struct edge{
 7     long long from,v;
 8 }e[maxn];
 9 
10 long long tot,first[maxn];
11 void insert(long long u,long long v){
12     tot++;
13     e[tot].from = first[u];
14     e[tot].v = v;
15     first[u] = tot;
16 }
17 
18 long long n,u,v,s[maxn],val[maxn],cnt1,cnt2,maxx[maxn],sum,ans;
19 int main(){
20     scanf("%lld",&n);
21     for(long long i = 1;i < n;i++){
22         scanf("%lld%lld",&u,&v);
23         insert(u,v);
24         insert(v,u);
25     }
26     
27     for(long long i = 1;i <= n;i++){
28         scanf("%lld",&val[i]);
29     }
30     
31     for(long long i = 1;i <= n;i++){
32         cnt1 = cnt2 = 0;
33         for(long long j = first[i];j;j = e[j].from){
34             v = e[j].v;
35             s[i] += val[v];
36 //            printf("$ %d",val[v]);
37             if(val[v] >= cnt1){
38                 cnt2 = cnt1,cnt1 = val[v];
39 //                printf("##%d %d",cnt1,cnt2);
40             }else if(val[v] > cnt2) cnt2 = val[v];
41         }
42 //        cout << endl;
43         maxx[i] = cnt1*cnt2;
44     }
45     
46     for(long long i = 1;i <= n;i++){
47         ans = max(maxx[i],ans);
48         for(long long j = first[i];j;j = e[j].from){
49             sum = (sum+(s[i]-val[e[j].v])*val[e[j].v]); sum %= 10007;
50         }
51         
52     }
53     
54     printf("%lld %lld\n",ans,sum);
55     
56 //    for(int i = 1;i <= n;i++) printf("%d ",maxx[i]);
57     
58     return 0;
59 }
易证Leo_CT相当菜= =

 

posted @ 2017-08-16 23:09  Leviaton  阅读(145)  评论(0编辑  收藏  举报