#NOIP 2014# day.1 T2 联合权值
2016-07-26 09:03
459 查看
题目和数据在评论中给出地址。或者自行在网上搜索,这里就不再给出。
第一眼看起来很复杂。
所以我想了个对链、和树不同情况都分别处理的算法。。orz。。复杂度太高最后4组T了。。
所以。。转换思路。。
联合权值 w[i]*w[j]。i,j距离为2.也就是i,j中间间隔了一个节点,所以我们在遍历这个中间节点的时候处理。
题目求最大和总和,
先考虑最大,我们只需要对节点U维护一个_max1,_max2最大值和次大值。
然后_max1*_max2 和总的 maxw比。maxw取大。
然后就是两两和。
先考虑U点只有3个子节点 a,b,c
则 tot = (a * b + b * c + c * a)*2 % mod
而(a + b + c)^2 = a^2 + b^2 + c^2 + 2ab + 2ac +2bc ;
2ab + 2ac +2bc = (a + b + c)^2 - (a^2 + b^2 + c^2 ).
所以..
再给出一份搜索的代码
第一眼看起来很复杂。
所以我想了个对链、和树不同情况都分别处理的算法。。orz。。复杂度太高最后4组T了。。
所以。。转换思路。。
联合权值 w[i]*w[j]。i,j距离为2.也就是i,j中间间隔了一个节点,所以我们在遍历这个中间节点的时候处理。
题目求最大和总和,
先考虑最大,我们只需要对节点U维护一个_max1,_max2最大值和次大值。
然后_max1*_max2 和总的 maxw比。maxw取大。
然后就是两两和。
先考虑U点只有3个子节点 a,b,c
则 tot = (a * b + b * c + c * a)*2 % mod
而(a + b + c)^2 = a^2 + b^2 + c^2 + 2ab + 2ac +2bc ;
2ab + 2ac +2bc = (a + b + c)^2 - (a^2 + b^2 + c^2 ).
所以..
#include <iostream> #include <cstdio> #include <cstdlib> #include <vector> #define maxn 600010 using namespace std; struct Edge { int v,next; }e[maxn]; long long p[maxn],w[maxn], en = 0; int f[maxn]; void add(int u, int v) { en ++; e[en].v = v; e[en].next = f[u]; f[u] = en; } int main() { freopen("link.in","r",stdin); freopen("link.out","w",stdout); int n,u,v; cin >> n; for (int i = 1; i <= n; ++i) f[i] = -1; for (int i = 1; i < n; ++i) { scanf("%d %d", &u, &v); add(u,v); add(v,u); } long long total = 0, max = 0; for (int i = 1; i <= n; ++i) scanf("%d", &w[i]); for (int i = 1; i <= n; ++i) { int cnt = 0; long long sum1= 0; int max1 = 0, max2 = 0; for (int j = f[i]; j != -1; j = e[j].next) { p[++cnt] = w[e[j].v]; sum1 = (sum1 + p[cnt]) % 10007; total = (total - p[cnt] * p[cnt] + 10007) % 10007; if (p[cnt] > max1) max2 = max1, max1 = p[cnt]; else if (p[cnt] > max2) max2 = p[cnt]; } if (cnt > 0) { total = (total + sum1 * sum1) % 10007; } if (total < 0) total += 10007; if (max1 * max2 > max) max = max1 * max2; } cout <<max<<" "<<total<<endl; return 0; }
再给出一份搜索的代码
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> #include<vector> #include<stack> using namespace std; int n; #define maxn 200001 #define mod 10007 vector<int> e[maxn]; int w[maxn]; int maxw = 0; int tot = 0; bool vis[maxn]; void dfs(int u,int fa) { vis[u] = 1; int len = e[u].size(); int _max1 = w[fa],_max2 = 0; int sum = 0,dsum = 0,v; for(int i=0;i<len;i++) { v = e[u][i]; if(!vis[v]&&v!=fa) { if(w[v]>_max1) { _max2 = _max1; _max1 = w[v]; } else if(w[v]>_max2) { _max2 = w[v]; } dfs(v,u); sum += w[v]; sum %= mod; dsum += w[v]*w[v]; dsum %= mod; } } tot += ((long long)sum*w[fa]*2)%mod; tot += ((long long)sum*sum%mod - dsum + mod)%mod; tot %= mod; maxw = max(maxw,_max1*_max2); } int main() { #define LOC #ifdef LOC freopen("link.in","r",stdin); freopen("link.out","w",stdout); #endif scanf("%d",&n); int a,b; int root = 0; maxw = 0; tot = 0; for(int i=1;i<n;i++) { scanf("%d%d",&a,&b); e[a].push_back(b); e[b].push_back(a); } for(int i=1;i<=n;i++)scanf("%d",&w[i]); w[0]=0; dfs(1,0); printf("%d %d",maxw,tot); return 0; }
相关文章推荐
- NOIP复习计划
- TYVJ1193 括号序列解题报告
- 对DP的一点感想
- wikioi1004 四子连棋 解题报告
- TYVJ P1870 [NOIP1998P2]阶乘和
- HDU 1063 Exponentiation
- ~二分答案~
- 我自己的noip复习(实时更新)
- 最长回文子串(转载自网易博客:鼻子很帅的猪)
- 信息竞赛学习笔记:POJ3579中位数(二分)
- NOIP2009 最优贸易
- 一道hash题
- NOIP2007 树网的核
- 排列组合基本公式
- Gray码生成
- 堆
- Noip 2014 提高组复赛 解题报告
- NOIP 2009提高组,迟来的题解.
- NOIP2011 铺地毯
- NOIP 2011 选择客栈