jzoj 3583. 【GDOI2014模拟】小A的树

来源:互联网 发布:yum 不支持python 2.7 编辑:程序博客网 时间:2024/05/29 08:15

Description

小A有一棵N个点的树,每个点都有一个小于2^20的非负整数权值。现在小A从树中随机选择一个点x,再随机选择一个点y(x、y可以是同一个点),并对从x到y的路径上所有的点的权值分别做and、or、xor运算,最终会求得三个整数。小A想知道,他求出的三个数的期望值分别是多少。

Input

输入文件包含多组测试数据。

第一行,一个整数T,表示测试数据的组数。

接下来的T节,每节表示一组测试数据,格式如下:

第一行,一个整数N。

第二行,N个整数,其中第i个整数表示第i个点的权值。

接下来的N-1行,每行两个整数a、b,表示树中有一条连接a、b的边。

Output

T行,每行三个实数,结果保留3位小数,其中第i行的三个实数表示由第i组测试数据求得的三个期望值(按照and、or、xor的顺序)。

Sample Input

1

4

1 2 3 4

1 2

2 3

2 4

Sample Output

0.875 4.250 3.375

Data Constraint

对于20%的数据,1<=N<=1000;

对于另外20%的数据,N个点构成一条链;

对于全部的数据,1<=N<=100000,1<=T<=5。

分析:
对于每一种运算,可以把每一位独立出来,给每一位生成一棵树,每个点的权值就是0或1,如果x到y的路径的运算结果为1,则该路径在该位有贡献。那么这棵树的贡献就是,part_sum*(2^k)/(n*n),k就是第k位。我们可以用树形dp求。设f[x,0/1],g[x,0/1],h[x,0/1]表示and,or,xor运算,从x子树内任意一点到x的路径最后结果为0/1的路径数,显然经过x的路径数就是两个不同儿子的状态相乘(这个状态自己推,是真的烦)。

我也不知道这个程序为什么在某些题库会RE,我用这个题库的数据在本地测表示毫无问题,搞了我3个半钟。如果知道可以在评论发。程序仅供参考。

代码:

const maxn=100001; maxv=20;type node=record  y,next:longint; end;var f,g,h:array [1..maxn,0..1] of int64; a:array [1..maxn,1..20] of integer; ls:array [1..maxn] of longint; adge:array [1..maxn*2] of node; v:array [1..maxn] of longint; t,n,i,m:longint; ef,eg,eh,c:extended; sumf,sumg,sumh:extended;procedure add(x,y:longint); begin  inc(m);  adge[m].y:=y;  adge[m].next:=ls[x];  ls[x]:=m; end;procedure dfs(x:longint;dep:longint); var t,i:longint; sf,sg,sh:array [0..1] of int64;begin f[x,0]:=0; f[x,1]:=0; g[x,0]:=0; g[x,1]:=0; h[x,0]:=0; h[x,1]:=0; sf[0]:=0; sh[0]:=0; sg[0]:=0; sf[1]:=0; sh[1]:=0; sg[1]:=0; f[x,a[x,dep]]:=1; g[x,a[x,dep]]:=1; h[x,a[x,dep]]:=1; t:=ls[x]; while t>0 do  begin   with adge[t] do    begin     if v[y]=dep-1 then      begin       v[y]:=v[y]+1;       dfs(y,dep);       if a[x,dep]=0 then        begin         f[x,0]:=f[x,0]+f[y,0];         f[x,1]:=f[x,1]+f[y,1];         g[x,0]:=g[x,0]+g[y,1]+g[y,0];         h[x,0]:=h[x,0]+h[y,0];         h[x,1]:=h[x,1]+h[y,1];         ef:=ef+sf[0]*f[y,1]+sf[1]*f[y,0];         eh:=eh+sh[1]*h[y,0]+sh[0]*h[y,1]+sh[1]*h[y,1];        end       else        begin         f[x,0]:=f[x,0]+f[y,1];         f[x,1]:=f[x,1]+f[y,0];         g[x,0]:=g[x,0]+g[y,0];         g[x,1]:=g[x,1]+g[y,1];         h[x,1]:=h[x,1]+h[y,0]+h[y,1];         ef:=ef+sf[0]*f[y,0]+sf[1]*f[y,1];         eg:=eg+sg[1]*g[y,1];         eh:=eh+(sh[0]+sh[1])*(h[y,0]+h[y,1]);        end;       sf[0]:=sf[0]+f[y,0];       sf[1]:=sf[1]+f[y,1];       sg[0]:=sg[0]+g[y,0];       sg[1]:=sg[1]+g[y,1];       sh[0]:=sh[0]+h[y,0];       sh[1]:=sh[1]+h[y,1];      end;     t:=next;    end;  end; if a[x,dep]=0 then  begin   ef:=ef+sf[1];   eh:=eh+sh[1];  end  else   begin    ef:=ef+sf[0]+0.5;    eg:=eg+sg[1]+0.5;    eh:=eh+sh[0]+sh[1]+0.5;   end;end;procedure main; var i,x,k,y,j:longint; pow:extended;begin readln(n); m:=0;  for i:=1 to n do  begin   read(x); k:=0;   while x>0 do    begin     inc(k);     a[i,k]:=x and 1;     x:=x shr 1;    end;   for j:=k+1 to 20 do    a[i,j]:=0;   ls[i]:=0; v[i]:=0;  end; for i:=1 to n-1 do  begin   readln(x,y);   add(x,y);   add(y,x);  end; sumf:=0; sumg:=0; sumh:=0; pow:=1; for i:=1 to 20 do  begin   ef:=0; eh:=0; eg:=0;   v[1]:=i;   dfs(1,i);   sumf:=sumf+pow*ef/n/n*2;   sumh:=sumh+pow*eh/n/n*2;   sumg:=sumg+pow*eg/n/n*2;   pow:=pow*2;  end; writeln(sumg:0:3,' ',sumh:0:3,' ',sumf:0:3);end;begin readln(t); for i:=1 to t do  main;end.
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 增高的锻炼方法 成人增高科学方法 如何增高身高 增高方法男生 增高运动计划 增高科学方法 怎样快速增高 吃什么能增高 女生增高方法 增高的有效方法 科学增高方法 运动增高训练 女生增高小妙招 怎样才能增高身高 儿童增高的办法 有没有增高的方法 怎么快速增高 怎样增高方法 增高有效方法 增高产品真的有用吗 如何有效的增高 用什么方法增高 怎样才可以增高 增高长高医院 人可以增高吗 有什么方法增高 如何可以增高 有什么增高的方法 有什么增高的产品 快速增高产品 增高的办法有哪些 哪里可以增高 长高增高方法 十七岁怎么增高 有没有增高的好方法 如何有效增高 医院增高有效吗 增高有什么好方法 增高产品哪个好 增高的好方法 增高医院有用吗