NOIP2014 聯合權值
阿新 • • 發佈:2019-01-27
兩個問題都需要按照每個節點的相鄰點來思考解法。
把符合題目要求的,可產生聯合權值的有序點對,稱為聯合點。
- 第一問
每個節點的子節點(相鄰點)之間,彼此組成聯合點,具體看圖。
可以比較每個節點的相鄰點的權值,得到最大子節點和次大子節點。
他們的聯合權值就是這個節點所能發現的最大聯合權值。
然後更新答案
- 第二問
直接兩兩相乘的話能得70分,剩下三個點會TLE
但其實我們需要的只是乘積的和
網上有加法分配律的演算法,但我這裡是難一點的…
設一個點u的相鄰點為a, b, c
那麼這個點能為答案貢獻
(聯合權值是重複的,如(1,3)和(3,1)都要算上)
我們要求的就是
這個值可以轉化為:
還要注意 如果不開long long 就要邊加邊模
#include <cstdio>
#include <algorithm>
const int maxn = 200010;
int tot=0,last[maxn],value[maxn];
bool vis[maxn];
int max1,max2,u,v,que,n,ans;
struct Edge{
int u,v,to;
Edge(){}
Edge(int u, int v, int to) : u(u), v(v), to(to) {}
}e[maxn*2+10];
void addedge(int u,int v) {
e[++tot] = Edge(u,v,last [u]);
last[u] = tot;
}
int main() {
scanf("%d",&n);
for(int i=1; i<=n-1; i++){
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
for(int i=1; i<=n; i++)
scanf("%d",&value[i]);
for(int u=1; u<=n; u++) {
int s1=0,s2=0,max1=0,max2=0;
for(int i=last[u]; i; i=e[i].to) {
int v = e[i].v;
if(value[v] > max1)
max1 = value[v];
else if(value[v] > max2)
max2 = value[v];
s1 = (s1%10007 + value[v]%10007) % 10007;
s2 = (s2%10007 + value[v]*value[v]%10007) % 10007;
}
ans = (ans%10007 + (s1*s1 - s2)%10007) % 10007;
que = std::max(que,max1*max2);
}
printf("%d %d",que,ans%10007);
return 0;
}