3573: [Hnoi2014]米特运输

Description
米特是D星球上一种非常神秘的物质,蕴含着巨大的能量。在以米特为主要能源的D星上,这种米特能源的运输和储存一直是一个大问题。
    D星上有N个城市,我们将其顺序编号为1到N,1号城市为首都。这N个城市由N-1条单向高速通道连接起来,构成一棵以1号城市(首部)为根的树,高速通道的方向由树中的儿子指向父亲。树按深度分层:根结点深度为0,属于第1层;根结点的子节点深度为1,属于第2层;依此类推,深度为i的结点属于第i+l层。
    建好高速通道之后,D星人开始考虑如何具体地储存和传输米特资源。由于发展程度不同,每个城市储存米特的能力不尽相同,其中第i个城市建有一个容量为A[i]的米特储存器。这个米特储存器除了具有储存的功能,还具有自动收集米特的能力。如果到了晚上六点,有某个储
存器处于未满的状态,它就会自动收集大气中蕴含的米特能源,在早上六点之前就能收集满;但是,只有在储存器完全空的状态下启动自动收集程序才是安全的,未满而又非空时启动可能有安全隐患。早上六点到七点间,根节点城市(1号城市)会将其储存器里的米特消耗殆尽。
根节点不会自动搜集米特,它只接受子节点传输来的米特。早上七点,城市之间启动米特传输过程,传输过程逐层递进:先是第2层节点城市向第1层(根节点城市,即1号城市)传输,直到第1层的储存器满或第2层的储存器全为空;然后是第3层向第2层传输,直到对于第2层的每个节点,其储存器满或其予节点(位于第3层)的储存器全为空;依此类推,直到最后一层传输完成。传输过程一定会在晚上六点前完成。
    由于技术原因,运输方案需要满足以下条件:

(1)不能让某个储存器到了晚上六点传输结束时还处于非空但又未满的状态,这个时候储存器仍然会启动自动收集米特的程序,而给已经储存有米特的储存器启动收集程序可能导致危险,也就是说要让储存器到了晚上六点时要么空要么满;

(2)关于首都——即1号城市的特殊情况,  每天早上六点到七点间1号城市中的米特储存器里的米特会自动被消耗殆尽,即运输方案不需要考虑首都的米特怎么运走;

(3)除了1号城市,每个节点必须在其子节点城市向它运输米特之前将这座城市的米特储存器中原本存有的米特全部运出去给父节点,不允许储存器中残存的米特与外来的米特发生混合;

(4)运向某一个城市的若干个来源的米特数量必须完全相同,不然,这些来源不同的米特按不同比例混合之后可能发生危险。
    现在D星人已经建立好高速通道,每个城市也有了一定储存容量的米特储存器。为了满足上面的限制条件,可能需要重建一些城市中的米特储存器。你可以,也只能,将某一座城市(包括首都)中屎来存在的米特储存器摧毁,再新建一座任意容量的新的米特储存器,其容量可以是小数(在输入数据中,储存器原始容量是正整数,但重建后可以是小数),不能是负数或零,使得需要被重建的米特储存器的数目尽量少。


Input
    第一行是一个正整数N,表示城市的数目。
    接下来N行,每行一个正整数,其中的第i行表示第i个城市原来存在的米特储存器的容量。
    再接下来是N-I行,每行两个正整数a,b表示城市b到城市a有一条高速通道(a≠b)。


Output
    输出文件仅包含一行,一个整数,表示最少的被重建(即修改储存器容量)的米特储存器的数目。


Sample Input


5
5
4
3
2
I
12
13
24
25

Sample Output
3
HINT

【样例解释】

  一个最优解是将A[1]改成8,A[3]改成4,A[5]改成2。这样,2和3运给1的量相等,4和5运

给2的量相等,且每天晚上六点的时候,1,2满,3,4,5空,满足所有限制条件。

 

  对于100%的数据满足N<500000,A[j]<10^8

囧,hnoi第一天好像很无语啊,基本上都是暴力

前两题搞了好久没想出来优化,所以想来打第三题的暴力

看样例了之后发现不对,把A[3]改成5不就行了吗,反正题意很混乱的感觉

搞了半天好像是这样的

给你一棵树,树上的点有权值,要求修改最少的点权,使得树满足两个条件

1.如果一个节点有儿子,那么这个节点的权值要等于儿子的权值和

2.如果一个节点有儿子,那么儿子的点权必须相等

所以设节点1的点权为X,那么我们可以算出每个节点的权值应为X/c[i](这个dfs一边就可以求出来)

然后我们枚举不变的点,然后可以通过c[i]和a[i]算出这个点权值不变时对应的X,然后hash,对应的X相同的点就不用改,然后把其他的都改一遍,因为容量可以为实数,所以就可以了

卧槽!要是考场上有这么清晰的思路,我第一天就160了(第一天有人AK,160就一点也不高了,出了成绩才知道,我这一题如果A了基本就是踩线上省队了..........囧)

考场上的时候逗逼了,求hash值写错了(我的想法是截取前面一段和后面一段比较,然后出来时发现这个做不了),然后50分......

好像hash取两个模就一定是对的,算出hash值,再排序就可以判断重复的了

  1 const
  2         name='meat';
  3         maxn=500010;
  4         h1=10000000000007;
  5         h2=999999999997;
  6 type
  7         node=record
  8           x,y:int64;
  9         end;
 10 
 11 var
 12         a:array[0..maxn]of int64;
 13         c:array[0..maxn]of node;
 14         first,next,last,size:array[0..maxn]of longint;
 15         n,ans,tot:longint;
 16 
 17 procedure insert(x,y:longint);
 18 begin
 19         inc(tot);
 20         inc(size[x]);
 21         last[tot]:=y;
 22         next[tot]:=first[x];
 23         first[x]:=tot;
 24 end;
 25 
 26 procedure dfs(x:longint;y,z:int64);
 27 var
 28         i:longint;
 29 begin
 30         c[x].x:=y*a[x] mod h1;
 31         c[x].y:=z*a[x] mod h2;
 32         y:=y*size[x] mod h1;
 33         z:=z*size[x] mod h2;
 34         i:=first[x];
 35         while i<>0 do
 36           begin
 37             dfs(last[i],y,z);
 38             i:=next[i];
 39           end;
 40 end;
 41 
 42 operator <(a,b:node)c:boolean;
 43 begin
 44         c:=(a.x<b.x) or ((a.x=b.x) and (a.y<b.y));
 45 end;
 46 
 47 operator =(a,b:node)c:boolean;
 48 begin
 49         c:=(a.x=b.x) and (a.y=b.y);
 50 end;
 51 
 52 procedure swap(var x,y:node);
 53 var
 54         t:node;
 55 begin
 56         t:=x;x:=y;y:=t;
 57 end;
 58 
 59 procedure sort(l,r:longint);
 60 var
 61         i,j:longint;
 62         y:node;
 63 begin
 64         i:=l;
 65         j:=r;
 66         y:=c[(l+r)>>1];
 67         repeat
 68           while c[i]<y do
 69             inc(i);
 70           while y<c[j] do
 71             dec(j);
 72           if i<=j then
 73           begin
 74             swap(c[i],c[j]);
 75             inc(i);
 76             dec(j);
 77           end;
 78         until i>j;
 79         if i<r then sort(i,r);
 80         if j>l then sort(l,j);
 81 end;
 82 
 83 procedure main;
 84 var
 85         i,x,y,k:longint;
 86 begin
 87         read(n);
 88         for i:=1 to n do
 89           read(a[i]);
 90         for i:=1 to n-1 do
 91           begin
 92             read(x,y);
 93             insert(x,y);
 94           end;
 95         dfs(1,1,1);
 96         sort(1,n);
 97         ans:=n;
 98         k:=0;
 99         for i:=1 to n do
100           begin
101             if (i=1) or (c[i]=c[i-1]) then inc(k)
102             else k:=1;
103             if ans>n-k then ans:=n-k;
104           end;
105         writeln(ans);
106 end;
107 
108 begin
109 assign(input,name+'.in');reset(input);
110 assign(output,name+'.out');rewrite(output);
111         main;
112 close(input);close(output);
113 end.
View Code
原文地址:https://www.cnblogs.com/Randolph87/p/3720753.html