【BZOJ1211】树的计数(Prufer编码)
题意:一个有n个结点的树,设它的结点分别为v1, v2, …, vn,
已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵。
其中1<=n<=150,输入数据保证满足条件的树不超过10^17个。
思路:
Martix67:
一个有趣的推广是,n个节点的度依次为D1, D2, …, Dn的无根树共有(n-2)! / [ (D1-1)!(D2-1)!..(Dn-1)! ]个,因为此时Prüfer编码中的数字i恰好出现Di-1次。
POPOQQQ:
注意此题无解需要输出0
当n!=1&&d[i]==0时 输出0
当Σ(d[i]-1)!=n-2时输出0
1 var a,b,prime,cnt:array[0..1000]of longint; 2 n,m,s,i:longint; 3 ans:int64; 4 flag:boolean; 5 6 function mult(x,y:longint):int64; 7 var tmp:int64; 8 begin 9 mult:=1; tmp:=x; 10 while y>0 do 11 begin 12 if y and 1=1 then mult:=mult*tmp; 13 tmp:=tmp*tmp; 14 y:=y>>1; 15 end; 16 end; 17 18 function ins(x,y:longint):longint; 19 var i,k:longint; 20 begin 21 for i:=1 to m do 22 begin 23 k:=x; 24 while k>0 do 25 begin 26 cnt[i]:=cnt[i]+k div prime[i]*y; 27 k:=k div prime[i]; 28 end; 29 end; 30 end; 31 32 function su(x:longint):boolean; 33 var i:longint; 34 begin 35 if x=2 then exit(true); 36 for i:=2 to trunc(sqrt(x)) do 37 if x mod i=0 then exit(false); 38 exit(true); 39 end; 40 41 begin 42 assign(input,'bzoj1211.in'); reset(input); 43 // assign(output,'bzoj1211.out'); rewrite(output); 44 readln(n); 45 for i:=2 to 150 do 46 if su(i) then begin inc(m); prime[m]:=i; end; 47 for i:=1 to n do 48 begin 49 read(a[i]); 50 inc(b[a[i]]); 51 s:=s+a[i]-1; 52 end; 53 if n-2<>s then 54 begin 55 writeln(0); 56 exit; 57 end; 58 flag:=true; 59 for i:=1 to n do 60 if a[i]=0 then begin flag:=false; break; end; 61 if (n>1)and( not flag) then 62 begin 63 writeln(0); 64 exit; 65 end; 66 67 ins(n-2,1); 68 for i:=1 to n do 69 if b[i]-1>0 then ins(b[i]-1,-1); 70 ans:=1; 71 for i:=1 to m do ans:=ans*mult(prime[i],cnt[i]); 72 writeln(ans); 73 74 close(input); 75 //close(output); 76 end.
null