[NOIP2014 提高组] 联合权值 题解
本题注意两个点:
- 如果
会产生联合权值, 也会产生相等的联合权值。 - 只有联合权值之和才
,最大联合权值不用(大坑点)。
对于求最大联合权值,相对简单。因为能产生联合权值的
for(int w = 1;w <= n;w++){//中转点
int max1 = -1,max2 = -1;//最大值、次大值
for(int i = head[w];i;i = e[i].nex){//遍历所有与w相邻的点
int v = e[i].to;
//打擂台找最大、次大(请自行分类讨论)
if(a[v] > max1){
max2 = max1;
max1 = a[v];
}
else if(a[v] > max2)
max2 = a[v];
}
ans_max = max(ans_max,max1 * max2);
}
对于联合权值之和,我们需要这么分析:
对于与当前中转点相邻的一对
对于与当前中转点相邻的三个点
依次类推,所有与
因此,我们遍历所有与
代码如下,注意要边加边取模:
for(int w = 1;w <= n;w++){//中转点
int sum1 = 0,sum2 = 0;//相邻节点权值和的平方、相邻节点权值的平方和
for(int i = head[w];i;i = e[i].nex){//遍历所有与w相邻的点
(sum1 += a[v]) %= MOD;
(sum2 += a[v] * a[v]) %= MOD;
}
sum1 = sum1 * sum1 % MOD;
(ans_tot += sum1 - sum2) %= MOD;
}
合并后完整代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 9,MOD = 10007;
struct edge{
int to,nex;
} e[N << 1];//建的是无向树,开两倍空间
int head[N],ecnt;
void addedge(int u,int v){//建边
ecnt++;
e[ecnt] = (edge){v,head[u]};
head[u] = ecnt;
}
int n;
int a[N];
int ans_max,ans_tot;//最大联合权值,联合权值之和
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n;
for(int i = 1;i < n;i++){
int u,v;
cin >> u >> v;
addedge(u,v);
addedge(v,u);
}
for(int i = 1;i <= n;i++)
cin >> a[i];
for(int w = 1;w <= n;w++){//中转点
int max1 = -1,max2 = -1;//最大值、次大值
int sum1 = 0,sum2 = 0;//相邻节点权值和的平方、相邻节点权值的平方和
for(int i = head[w];i;i = e[i].nex){//遍历所有与w相邻的点
int v = e[i].to;
if(a[v] > max1){
max2 = max1;
max1 = a[v];
}
else if(a[v] > max2)
max2 = a[v];
(sum1 += a[v]) %= MOD;
(sum2 += a[v] * a[v]) %= MOD;
}
sum1 = sum1 * sum1 % MOD;
(ans_tot += sum1 - sum2) %= MOD;
ans_max = max(ans_max,max1 * max2);
}
cout << ans_max << ' ' << (ans_tot % MOD + MOD) % MOD;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具