【洛谷】1351 [Noip2014] 联合权值 枚举

22 篇文章 0 订阅
1 篇文章 0 订阅

题目传送门

日常水一水,挑一道Noip的水题来练练手。

这题的题意是求一棵树上所有的由两条边相连的点对的点权积的和,还有点权积的最大值。

我们可以单独挑出一个点i,假设有4个点v1,v2,v3,v4和它直接相连,那么第i号节点对点权积和的贡献S可以表示成:

S=W(v1)*W(v2)+W(v1)*W(v3)+W(v1)*W(v4)+W(v2)*W(v3)+W(v2)*W(v4)+W(v3)*W(v4)

把右边的式子变形一下,得:S=W(v2)*W(v1)+W(v3)*(W(v1)+W(v2))+W(v4)*(W(v1)+W(v2)+W(v3))

这下就好办了,我们可以枚举所有节点i,然后枚举所有与第i号节点直接相连的节点j,k表示之前枚举的和第i号节点直接相连的节点,那么ans+=W(j)*ΣW(k)。

求点权积的最大值,这个嘛,就不用我说了吧。

附上AC代码:

#include <cstdio>
#define p 10007
#define N 200010
using namespace std;

struct side{
	int to,nt;
}s[N<<1];
int n,x,y,ans,num,h[N],a[N],mx1,mx2,sum,mx;

inline void add(int x,int y){
	s[++num]=(side){y,h[x]},h[x]=num;
	s[++num]=(side){x,h[y]},h[y]=num;
}

inline int max(int a,int b){return a>b?a:b;}

int main(void){
	scanf("%d",&n);
	for (int i=1; i<n; ++i) scanf("%d%d",&x,&y),add(x,y);
	for (int i=1; i<=n; ++i) scanf("%d",&a[i]);
	for (int i=1; i<=n; ++i){
		sum=mx1=mx2=0;
		for (int j=h[i]; j; j=s[j].nt){
			ans=(ans+sum*a[s[j].to])%p,sum=(sum+a[s[j].to])%p;
			if (a[s[j].to]>=mx1) mx2=mx1,mx1=a[s[j].to];
				else if (a[s[j].to]>mx2) mx2=a[s[j].to];
		}
		mx=max(mx,mx1*mx2);
	}
	printf("%d %d",mx,(ans<<1)%p);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值