bzoj 1005 prufer编码+排列组合+高精

来源:互联网 发布:淘宝联盟推广没有图片 编辑:程序博客网 时间:2024/05/16 16:15

题意:n个点,允许任意两点连边,给出某些点最终的度数,求所有满足要求的树的个数

先介绍prufer编码:

(一)将树转成prufer编码

任意一棵n个点的树都会转成长度为(n-2)prufer编码

度数为m的点,在prufer编码中出现的次数为m-1

第i布时,删去叶子节点中标号最小的点及与它相连的边,并把与它相邻的点加入prufer数列

(二)将prufer编码转成树

设{a1,a2,..an-2}为一棵有n个节点的树的Prufer序列,同时新建集合G{1..n},找出G集合中未在Prufer序列中出现过的最小的数,将该点与Prufer序列中首项连一条边,并将该点和Prufer序列首项删除,重复操作n-2次,最后将G集合中剩余的两个点之间连边即可。

然后我们回归题目

我们用d[i]表示i点要求的最终度数

令 tot=sigma(d[i]-1) (d[i]<>-1) ; m=sigma(1) (d[i]=-1)

根据定义,当tot>n-2 或者 当m=0且tot!=n-2 时,是不合法的,无解

根据排列组合可知 ans=C(n-2,tot)*C(tot,d1-1)*C(tot-d1+1,d2-1)*...*C(dn-1,dn-1)*m^(n-2-tot)

化简可得 ans=(n-2)!*m^(n-2-tot)/((n-2-tot)!*(d1-1)!*(d2-1)!*..*(dn-1)!)

然后蒟蒻发现要写高精除果断弃疗...

然后果断%%%hzwer(一下截自黄学长博客)

var        n,m,tot,x       :longint;        i,j             :longint;        vis             :array[0..1010] of boolean;        prime           :array[0..1010] of longint;        up,down,mid     :array[0..1010] of longint;        ans             :array[0..500010] of longint;procedure pre_do;var        i:longint;begin   for i:=2 to n do   begin      if not vis[i] then      begin         inc(prime[0]);         prime[prime[0]]:=i;      end;      for j:=1 to prime[0] do        if i*prime[j]>n then break else        begin           vis[i*prime[j]]:=true;           if i mod prime[j]=0 then break;        end;   end;end;procedure calcdown(x:longint);var        tt,i:longint;begin   for i:=1 to prime[0] do   begin      if prime[i]>x then exit;      tt:=prime[i];      while tt<=x do      begin         inc(down[i],x div tt);         tt:=tt*prime[i];      end;   end;end;procedure calcup(x:longint);var        tt,i:longint;begin   for i:=1 to prime[0] do   begin      if prime[i]>x then exit;      tt:=prime[i];      while tt<=x do      begin         inc(up[i],x div tt);         tt:=tt*prime[i];      end;   end;end;procedure cheng(x:longint);var        i,tt:longint;begin   for i:=1 to ans[0] do ans[i]:=ans[i]*x;   tt:=0;   for i:=1 to ans[0] do   begin      inc(ans[i],tt);      tt:=ans[i] div 10000;      ans[i]:=ans[i] mod 10000;   end;   while tt<>0 do   begin      inc(ans[0]);      ans[ans[0]]:=tt mod 10000;      tt:=tt div 10000;   end;end;procedure qc(a,b:longint);begin   if b=0 then exit;   if (b and 1=1) then cheng(a);   if b=1 then exit;   qc(a,b>>1);   qc(a,b>>1);end;begin   read(n);   pre_do;   for i:=1 to n do   begin      read(x);      if x=-1 then inc(m) else      begin         inc(tot,x-1);         calcdown(x-1);      end;   end;   //   if (tot>n-2) or ((m=0) and (tot<>n-2)) then   begin      writeln(0); exit;   end;   //   if n-2-tot<>0 then calcdown(n-2-tot);   if n-2<>0 then calcup(n-2);   ans[0]:=1; ans[1]:=1;   for i:=1 to prime[0] do mid[i]:=up[i]-down[i];   for i:=1 to prime[0] do     if mid[i]>0 then qc(prime[i],mid[i]);   qc(m,n-2-tot);   //   write(ans[ans[0]]);   for i:=ans[0]-1 downto 1 do   begin      if ans[i]<1000 then write(0);      if ans[i]<100 then write(0);      if ans[i]<10 then write(0);      write(ans[i]);   end;   writeln;end.
——by Eirlys



0 0
原创粉丝点击