【BZOJ1005】【HNOI2008】明明的烦恼

【Description】

  自从明明学了树的结构,就对奇怪的树产生了兴趣…… 给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树?


【Input】

  第一行为N(0 < N < = 1000),接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1


【Output】

  一个整数,表示不同的满足要求的树的个数,无解输出0


【Sample Input】

3
1
-1
-1

【Sample Output】

2

【Solution】

  Prufer编码。详见:怡红公子
  
  代码如下:

/**************************************************************
    Problem: 1005
    User: llgyc
    Language: Pascal
    Result: Accepted
    Time:36 ms
    Memory:240 kb
****************************************************************/

const mo = 10000;
type HP=array[0..1005] of longint;
var n,m,cnt,tot:longint;
    prime,num,d:array[0..1005] of longint;
    ans:HP;
function judge(x:longint):boolean;
  var i:longint;
  begin
    for i:=2 to trunc(sqrt(x)) do
      if x mod i=0 then exit(false);
    exit(true);
  end;
procedure prep();
  var i:longint;
  begin
    for i:=2 to 1000 do
      if judge(i) then begin inc(cnt); prime[cnt]:=i; end;
    ans[0]:=1; ans[1]:=1;
  end;
procedure extract(x,p:longint);
  var i,j,tmp:longint;
  begin
    for i:=1 to x do begin
      tmp:=i;
      for j:=1 to cnt do begin
        if tmp<=1 then break;
        while (tmp mod prime[j]=0) do begin tmp:=tmp div prime[j]; num[j]:=num[j]+p; end;
      end;
    end;
  end;
procedure print(x:HP);
  var i:longint;
  begin
    write(x[x[0]]);
    for i:=x[0]-1 downto 1 do begin
      if x[i]<1000 then write(0);
      if x[i]<100 then write(0);
      if x[i]<10 then write(0);
      write(x[i]);
    end; writeln;
  end;
procedure mul(var a:HP; b:longint);
  var c:HP;
      i:longint;
  begin
    fillchar(c,sizeof(c),0);
    c[0]:=a[0];
    for i:=1 to c[0] do begin
      c[i]:=c[i]+a[i]*b;
      c[i+1]:=c[i] div mo;
      c[i]:=c[i] mod mo;
    end;
    while (c[c[0]+1]>0) do begin
      inc(c[0]); c[c[0]+1]:=c[c[0]] div mo; c[c[0]]:=c[c[0]] mod mo;
    end;
    a:=c;
  end;
procedure main();
  var x,i,j:longint;
  begin
    if n=1 then begin
      readln(x);
      if x=0 then writeln(1) else writeln(0);
      exit;
    end;
    for i:=1 to n do begin
      readln(d[i]);
      if d[i]=0 then begin writeln(0); exit; end;
      if d[i]=-1
        then inc(m)
        else begin dec(d[i]); inc(tot,d[i]); end;
    end;
    if tot>n-2 then begin writeln(0); exit; end;
    fillchar(num,sizeof(num),0);
    extract(n-2,1); extract(n-2-tot,-1); for i:=1 to n do if d[i]>0 then extract(d[i],-1);
    for i:=1 to cnt do
      for j:=1 to num[i] do mul(ans,prime[i]);
    for i:=1 to n-2-tot do mul(ans,m);
    print(ans);
  end;
begin
  prep();
  readln(n);
  main();
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值