题意:n个点,允许任意两点之间连边,给定每个点的最终度数,求所有满足要求的树的个数
bzoj 1005的简化版,关于prufer序列及答案化简请戳(我才不说我是懒得写了呢...)
因为所有点都有要求,注意特判不合法的情况:
(1)sigma(d[i]-1)<>n-2
(2) (d[i]=0) && (n<>1)
var
n,x,tot :longint;
ans :int64;
i :longint;
prime :array[0..110] of longint;
vis :array[0..210] of boolean;
num :array[0..110] of longint;
procedure pre_do;
var
i,j: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
dec(num[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(num[i],x div tt);
tt:=tt*prime[i];
end;
end;
end;
function qp(a,b:longint):int64;
var
ans:int64;
begin
ans:=1;
while b>0 do
begin
if b and 1=1 then ans:=ans*a;
a:=a*a;
b:=b>>1;
end;
exit(ans);
end;
begin
read(n);
pre_do;
for i:=1 to n do
begin
read(x);
if (x=0) and (n<>1) then
begin
writeln(0); exit;
end;
inc(tot,x-1);
calcdown(x-1);
end;
if (tot<>n-2) then
begin
writeln(0); exit;
end;
calcup(n-2);
ans:=1;
for i:=1 to prime[0] do
if num[i]>0 then ans:=ans*qp(prime[i],num[i]);
writeln(ans);
end.
——by Eirlys