其他分享
首页 > 其他分享> > 【题解&&海亮集训&&dp】 洛谷 P1351 联合权值

【题解&&海亮集训&&dp】 洛谷 P1351 联合权值

作者:互联网

题目传送门

题目描述:
无向连通图 GGG 有 nnn 个点,n−1n-1n−1 条边。点从 111 到 nnn 依次编号,编号为 iii 的点的权值为 WiW_iWi​,每条边的长度均为 111。图上两点 (u,v)(u, v)(u,v) 的距离定义为 uuu 点到 vvv 点的最短距离。对于图 GGG 上的点对 (u,v)(u, v)(u,v),若它们的距离为 222,则它们之间会产生Wv×WuW_v \times W_uWv​×Wu​ 的联合权值。
请问图 GGG 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?


输入输出格式

输入格式:
第一行包含 111 个整数 nnn。
接下来 n−1n-1n−1 行,每行包含 222 个用空格隔开的正整数 u,vu,vu,v,表示编号为 uuu 和编号为 vvv 的点之间有边相连。
最后 111 行,包含 nnn 个正整数,每两个正整数之间用一个空格隔开,其中第 iii 个整数表示图 GGG 上编号为 iii 的点的权值为 WiW_iWi​。


输出格式:
输出共 111 行,包含 222 个整数,之间用一个空格隔开,依次为图 GGG 上联合权值的最大值和所有联合权值之和。由于所有联合权值之和可能很大,输出它时要对100071000710007取余。


分析:因为题目说两个点之间的距离为2就是一个有序数对,所以我们就可以知道一对有序序对之间必定隔着一个中转点,例如下图:
在这里插入图片描述其中1、2、3、4互为序对,因为它们都隔着一个中转点5,它们之间的距离都为2,所以做这道题的基础就是枚举中转点,它延伸出去的点必定互为序对。

那么枚举的问题解决了,这回我们就需要想算的问题。
第一个求最大值很好理解,我们只需要枚举中间点,在枚举它延伸出去的点,然后找一个最大值和次大值就可以了。
例如上图中的最大值就是 c*d=12;

第二个问题需要用到乘法的一些定则。
举个例子:
上图的和为ab+ac+ad+ba+bc+bd+ca+cb+cd+da+dc+dba*b+a*c+a*d+b*a+b*c+b*d+c*a+c*b+c*d+d*a+d*c+d*ba∗b+a∗c+a∗d+b∗a+b∗c+b∗d+c∗a+c∗b+c∗d+d∗a+d∗c+d∗b
经过整理可以变成:
ab+ac+ad+bc+bd+cd2(a*b+a*c+a*d+b*c+b*d+c*d)*2(a∗b+a∗c+a∗d+b∗c+b∗d+c∗d)∗2
再经过整理可以变成:
a(b+c+d)+b(c+d)+cd2(a*(b+c+d)+b*(c+d)+c*d)*2(a∗(b+c+d)+b∗(c+d)+c∗d)∗2
所以我们发现求和只需要用一个sum记录前几个数求得的和,然后不停的用后面的数累乘即可,具体的证明可以用乘法分配律展开求得。

不过求得后最后的乘2不能忘掉,这也是一个坑点。

那么具体代码如下:

#include<bits/stdc++.h>
using namespace std;
#define P 10007
struct node{
    int next,y;
}e[1000001];
int v[1000001];
int n;
int linkk[10000001];
int len;
void insert(int xx,int yy){
    e[++len].next=linkk[xx];
    linkk[xx]=len;
    e[len].y=yy;
}
int main(){
    scanf("%d",&n);
    for (int i=1,x,y;i<n;i++) scanf("%d %d",&x,&y),insert(x,y),insert(y,x);
    int ans=0,maxx=0;
    for (int i=1;i<=n;i++) scanf("%d",&v[i]);
    for (int i=1;i<=n;i++){
    	int max1=0,max2=0,sum=0;
	    int t=linkk[i];
	    for (int j=t;j;j=e[j].next){
		    if (v[e[j].y]>max1) max2=max1,max1=v[e[j].y];
		    else max2=max(max2,v[e[j].y]);
		    ans=(ans+sum*v[e[j].y])%P;
		    sum=(sum+v[e[j].y])%P;
		}
		maxx=max(maxx,max1*max2);
	}
	printf("%d %d",maxx,(ans*2)%P);
	return 0;
}

标签:洛谷,int,题解,sum,GGG,111,&&,权值,1n
来源: https://blog.csdn.net/huang_ke_hai/article/details/86682061