P1351 [NOIP2014 提高组] 联合权值 题解 错题分析

P1351 [NOIP2014 提高组] 联合权值 题解

联合权值

题意

在这里插入图片描述

思路

  1. 距离为2才计算权值,我们直接枚举开头会很麻烦,我们可以枚举中间点,计算从这个点出发的其他点的权值积即可
  2. 在计算权值积的和的时候,两层循环暴力算会超时,我们可以找规律,发现以某个节点为中转点的联合权值之和等于权值和的平方减去权值的平方和,比如以p出发有三个点{a,b,c},那么他们之间的和就是 (a+b+c)(a+b+c) - (aa)-(bb)-(cc)
  3. 计算最大权值积时,只需要保存最大两个点即可
  4. 在mod时权值积的和需要,而算最大不用

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
typedef long long ll;
vector<int> v[N];
ll mod = 10007;
ll dp[N],dp2[N],W[N],vis[N];//dp[i]是以i开始的累加和,dp2[i]是最大值 
void dfs(int u){
	ll max1 = 0, max2 = 0,sum = 0,sum2 = 0;
	for(int i : v[u]){ 
		sum += W[i]%mod;
		sum2 += W[i]*W[i]%mod; 
		if(W[i]>max1) max2 = max1,max1 = W[i];  
		else if(W[i]>max2) max2 = W[i];
	}
	dp[u] = (sum*sum%mod-sum2)%mod;
	dp2[u] = max1*max2; 
}
int main(){
	int n;
	cin>>n;
	for(int i = 1;i<n;i++){
		int a,b;
		cin>>a>>b;
		v[a].push_back(b);
		v[b].push_back(a);
	}
	for(int i = 1;i<=n;i++) cin>>W[i];
	ll ans = 0,ans_max = 0;
	for(int i = 1;i<=n;i++){
			dfs(i);
			ans_max = max(dp2[i],ans_max);
			ans = (ans+dp[i])%mod;
		
	}
	cout<< ans_max <<" "<<(ans+mod)%mod<<endl;
	return 0;
}

经验总结

  1. 题意的转化,在一开始想的时候,我是直接枚举开头节点然后去找距离为2的点,但是这样会超时,相当于两层循环,但是要注意到题目说是距离为 2 ,这样直接枚举中间的点,它的所有相邻点都是距离为2的点
  2. 其次,在计算权值积的时候,一开始我也是两层暴力枚举,也会超时,没有注意到运用数学公式简化计算过程,以后遇到这种情况,要试着总结公式简化运算
  3. 审题还是关键,哪里要mod,哪里不用mod
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值