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

    NOIP2014day1有个题目叫联合权值

    题目描述

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

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

    输入格式

      第一行包含 1 个整数 n。

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

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

    输出格式

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

    样例输入

    1 2 

    2 3 

    3 4 

    4 5 

    1 5 2 3 10 

    样例输出

    20 70

    限制

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

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

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

    这么一道题,有一个很显而易见的做法,N^2枚举,当然,只能拿60分

    题目上说n-1条边的无向连通图,实际上就是告诉我们这是一棵树,那么很显然是不存在环的

    而距离为2的点,实际上就是与每个点直接存在边相连的任意两个不同点

    那么很轻易可以想到要枚举中间点,然后对于它周围一圈的点进行计算

    因为是树不存在环,所以可以确保计算不重复

    最大值很轻易,就是周围一圈点中最大两个点的乘积取最大值

    那么剩下就是求和的问题了

    如果不考虑时间和空间,就是双重循环跑一趟就好了

    然后可以发现,对于周围这一圈每个点都要与其他点相乘

    那么对于每个点,设sum=周围一圈点的权值和,Wi

    又因为是有序点对,(i,j)和(j,i)被认为不同

    那么每个点对答案都有一个Wi*(sum-Wi)的贡献,那么只要跑一趟就可以了

    复杂度是O(N)的,因为每条边最多两次被参与计算

    代码在下面

     const tt=10007;
     var link,a:array[0..200005]of longint;
         son,next:array[0..400005]of longint;
         n,tot,ans1,ans:longint;
     procedure add(x,y:longint);
      begin
       inc(tot);son[tot]:=y;next[tot]:=link[x];link[x]:=tot;
      end;
     procedure init;
      var x,y,i,j:longint;
       begin
        assign(input,'link.in');reset(input);
        assign(output,'link.out');rewrite(output);
        fillchar(link,sizeof(link),0);
        readln(n);
        tot:=0;
        for i:=1 to n-1 do
         begin
          readln(x,y);
          add(x,y);add(y,x);
         end;
        for i:=1 to n do read(a[i]);
       end;
     procedure main;
      var i,j,x,y,sum:longint;
       begin
        a[0]:=0;
        ans:=0;ans1:=0;
        for i:=1 to n do
         begin
          sum:=0;x:=0;
          j:=link[i];
          while j<>0 do
           begin
            if a[son[j]]>a[x] then x:=son[j];
            sum:=(sum+a[son[j]])mod tt;
            j:=next[j];
           end;
          j:=link[i];y:=0;
          while j<>0 do
           begin
            if (a[son[j]]>a[y])and(son[j]<>x) then y:=son[j];
            ans:=(ans+a[son[j]]*(sum+tt-a[son[j]]))mod tt;
            j:=next[j];
           end;
           if a[x]*a[y]>ans1 then ans1:=a[x]*a[y];
         end;
        end;
     procedure print;
      begin
       writeln(ans1,' ',ans);
       close(input);close(output);
      end;
     begin
      init;
      main;
      print;
     end.

    还发生了小插曲

    我写好后,测评只有20

    和学长认认真真检查了一个晚上,发现取模错了,应该对10007,我写成了70007

    然后好不服,因为百度文库点开的题目就是70007

    最后,学长语重心长的说“听我的,撞墙吧,网上几千份,你刚好点开了错了”

    QAQ尴尬

    【写的有漏洞的,欢迎路过大神吐槽】

    2016-11-01 13:37:00

    Ending.

  • 相关阅读:
    阿里云服务器搭建之绑定多个域名
    centos7下yum安装mysql
    Mac 升级之后 无法通过域名 SSH 连接
    【课程章节更新】突破 没有支付权限的小程序 完成支付闭环
    每次sudo su切换root用户,都要source /etc/profile
    那些让你震惊的网站
    bootstrap select2使用模态框,搜索框无法输入问题解决
    新浪图片停止外链后的一些解决办法
    Yii2 报错 Headers already sent in
    使用Python Flask 开发微信机器人
  • 原文地址:https://www.cnblogs.com/wry0112/p/6019144.html
Copyright © 2011-2022 走看看