• P1351 联合权值


    P1351 联合权值

    题目描述
    无向连通图 GG 有 nn 个点, n-1n−1 条边。点从 11 到 nn 依次编号,编号为 ii 的点的权值为 W_iW
    i
    ​ ,每条边的长度均为 11 。图上两点 (u, v)(u,v) 的距离定义为 uu 点到 vv 点的最短距离。对于图 GG 上的点对 (u, v)(u,v) ,若它们的距离为 22 ,则它们之间会产生 W_v imes W_uW
    v
    ​ ×W
    u
    ​ 的联合权值。

    请问图 GG 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?

    输入输出格式
    输入格式:
    第一行包含 1 个整数 n 。

    接下来 n-1 行,每行包含 22 个用空格隔开的正整数 u,v u,v ,表示编号为 u和编号为 v 的点之间有边相连。

    最后 1 行,包含 n 个正整数,每两个正整数之间用一个空格隔开,其中第 ii 个整数表示图 G 上编号为 ii 的点的权值为 W_i

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


    这题思维还不错。首先我们可以想到一个很浅显的算法:dfs每一个点,到第二层是累加(sum),更新(max),复杂度(O(n^{2})),得到(60pnts)

    好了现在继续分析:因为这是一棵树,对于每一个点,它当作“桥梁”时,连接了若干个点,对于连接的任意两点,他们能构成联合权值

    很显然依据贪心,我们可以在线性时间内求出最大值和第二大值,他们相乘即为这个桥梁能产生的最大联合权值

    好的,最大联合权值解决了,现在我们解决联合权值之和

    对于某一个节点(我们把它叫做(1),这个“桥梁”连接的所有点编号为(1 - n)),他产生的权值之和为:

    (A[1] = w[1] * w[2] + w[1] * w[3]+ ... + w[1] * w[n])

    ( = w[1] * sum_{i = 1} ^ {n}w[i],i otin 1)

    ( = (sum_{i = 1} ^ {n}w[i] * w[1] ) - w[1] ^ {2})

    所以这一桥梁所有点产生的联合权值为:

    (ans =(sum_{i = 1}^{n}w[i])^{2} - sum_{i = 1}^{n}w[i]^{2})

    这题还要培养看清楚题的好习惯啊,题目上说了,只有联合权值之和要取模

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    typedef long long LL;
    using namespace std;
    int RD(){
        int out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const int Maxn = 1000019,INF = 1e9, M = 10007;
    int head[Maxn],nume = 1;
    struct Node{
        int v,dis,nxt;
        }E[Maxn << 3];
    void add(int u,int v,int dis){
        E[++nume].nxt = head[u];
        E[nume].v = v;
        E[nume].dis = dis;
        head[u] = nume;
        }
    int num,w[Maxn];
    LL ans,sum;
    void find(int u){
    	int Max = 0,Maxx = 0;
    	LL tot = 0;
    	for(int i = head[u];i;i = E[i].nxt){
    		int v = E[i].v;
    		tot = (tot + w[v]) % M;
    		if(w[v] >= Maxx)Max = Maxx,Maxx = w[v];
    		else if(w[v] > Max)Max = w[v];
    		}
    	ans = max(ans,Maxx * Max * 1ll);
    	tot = tot * tot % M;
    	for(int i = head[u];i;i = E[i].nxt){
    		int v = E[i].v;
    		tot -= (w[v] * w[v]) % M;
    		}
    	sum = (sum + tot) % M;
    	}
    int main(){
    	num = RD();
    	for(int i = 1;i <= num - 1;i++){
    		int u = RD(),v = RD();
    		add(u,v,1),add(v,u,1);
    		}
    	for(int i = 1;i <= num;i++)w[i] = RD();
    	for(int i = 1;i <= num;i++)find(i);
    	printf("%lld %lld
    ",ans,(sum + M) % M);
    	return 0;
    	}
    
  • 相关阅读:
    运动世界校园破解2.0
    Docker进阶操作
    一键开启https
    Docker的第一次实践总结
    手机通话黑屏
    mysql安装、操作、配置、远程
    excel添加列数据导入后,列数据不显示的问题
    常见邮箱的各类协议服务器地址
    POP3/SMTP/IMAP等邮箱协议的基本概念
    You credentials did not work (The logon attempt failed)
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9301787.html
Copyright © 2020-2023  润新知