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 }
转载请注明出处 -- 如有意见欢迎评论