zoukankan      html  css  js  c++  java
  • noip2014 联合权值

    P1351 联合权值

      • 914通过
      • 3.2K提交
    • 题目提供者该用户不存在
    • 标签动态规划树形结构2014NOIp提高组
    • 难度普及+/提高

    提交该题 讨论 题解 记录

    最新讨论

    • 暂时没有讨论

    题目描述

    无向连通图G 有n 个点,n - 1 条边。点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 。图上两点( u , v ) 的距离定义为u 点到v 点的最短距离。对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu

    ×Wv 的联合权值。

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

    输入输出格式

    输入格式:

    输入文件名为link .in。

    第一行包含1 个整数n 。

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

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

    输出格式:

    输出文件名为link .out 。

    输出共1 行,包含2 个整数,之间用一个空格隔开,依次为图G 上联合权值的最大值

    和所有联合权值之和。由于所有联合权值之和可能很大,[b]输出它时要对10007 取余。 [/b]

    输入输出样例

    输入样例#1:
    5  
    1 2  
    2 3
    3 4  
    4 5  
    1 5 2 3 10 
    输出样例#1:
    20 74

    说明

    本例输入的图如上所示,距离为2 的有序点对有( 1,3) 、( 2,4) 、( 3,1) 、( 3,5) 、( 4,2) 、( 5,3) 。

    其联合权值分别为2 、15、2 、20、15、20。其中最大的是20,总和为74。

    【数据说明】

    对于30% 的数据,1 < n≤ 100 ;

    对于60% 的数据,1 < n≤ 2000;

    对于100%的数据,1 < n≤ 200 , 000 ,0 < wi≤ 10, 000 。

    分析:注意到n个点n-1条边,说明了这是一棵树,每两个点之间只有一条路径,因为距离为2,这一条路径必定经过一个点,而这两个点在这一个点的左右,那么思路来了,我们可以枚举中间的一个点,然后枚举它所连到的另外两个点,去最大值和第二大值.可以用邻接表来实现.那么怎么求和最好呢?假设一个点与a,b,c相连.那么和就是a * b + a * c + b * a + b * c + c * a + c * b = a * (b + c) + b * (a + c) + c * (a + b),可以注意到这是一个对称式,a,b,c是不能化简得,那么后一项发现是总的和减去前一项,那么算法就出来了,设o = a + b + c,那么sum = a * (o - a) + b * (o - b) + c * (o - c),不过注意到和需要取余,以前我比较恶心取余的题,但是现在知道了一个技巧,凡是结果可能大于mod的数就取余,此题还有一个坑点就是权值可能就是负数,那么就要加上mod再取余.

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 200010,mod = 10007;
    
    int n,w[maxn],tot,head[maxn],nextt[maxn * 2],to[maxn * 2],sum,max1,max2,ans1,ans2;
    
    void add(int a, int b)
    {
        to[++tot] = b;
        nextt[tot] = head[a];
        head[a] = tot;
    }
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 1; i <= n - 1; i++)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u);
        }
        for (int i = 1; i <= n; i++)
            scanf("%d", &w[i]);
        for (int i = 1; i <= n; i++)
        {
            max1 = max2 = -1;
            sum = 0;
            for (int j = head[i]; j; j = nextt[j])
            {
                int temp = w[to[j]];
                sum += temp;
                sum %= mod;
                if (temp > max1)
                {
                    max2 = max1;
                    max1 = temp;
                }
                else if (temp > max2)
                    max2 = temp;
            }
            ans2 = max(ans2, max1 * max2);
            for (int j = head[i];j;j = nextt[j])
            {
                ans1 += (w[to[j]] * (sum - w[to[j]])) % mod;
                ans1 %= mod;
            }
        }
        ans1 = (ans1 + mod) % mod;
        printf("%d %d
    ", ans2, ans1);
    
        return 0;
    }
  • 相关阅读:
    BZOJ2219数论之神——BSGS+中国剩余定理+原根与指标+欧拉定理+exgcd
    Luogu 3690 Link Cut Tree
    CF1009F Dominant Indices
    CF600E Lomsat gelral
    bzoj 4303 数列
    CF1114F Please, another Queries on Array?
    CF1114B Yet Another Array Partitioning Task
    bzoj 1858 序列操作
    bzoj 4852 炸弹攻击
    bzoj 3564 信号增幅仪
  • 原文地址:https://www.cnblogs.com/zbtrs/p/5750387.html
Copyright © 2011-2022 走看看