时间限制:1000MS内存限制:256000KB
题目描述
lyh童鞋的手办非常多,以至于他专门种了一棵树来放置手办╮(╯▽╰)╭ 为了展现自己的收藏lyh决定从收藏树上选取一些手办展示
已知lyh的每个手办都有不同的美丽值,第i个节点上有一个美丽值为ai的手办。lyh认为一种选取手办的方案是合法的当且仅当选出的手办在树上联通,且满足连通块的最大美丽值与最小美丽值之差恰好等于k,两个选取方案不同当且仅当至少存在一个手办在一个方案中出现而另一个方案中没有出现。
痴迷于AK的你马上接下这道题目,在lyh期盼的眼神中,你切掉这道题的决心更加坚定了,现在就差你的代码了。
输入
第一行两个整数n,k,表示树的大小以及题目中的k。
第二行n个整数,第i个整数表示ai。
接下来n-1行,每行两个整数x,y表示树边(x,y)。
输出
一行一个整数,表示答案,答案对19260817取模。
输入样例复制
5 3
1 2 3 4 5
1 2
1 3
2 4
2 5
输出样例复制
4
说明
Data Constraint 对于30%的数据,n<=22 对于另外20%的数据,树是一条链 对于另外20%的数据,ai只有0和1两种 对于100%的数据,N<=3333,0<=ai<=N,K>=0
题解:树形dp
为保证方案不重复,枚举每一个点,令f[i]以i为根,a[i]为最大值,子树所有点与a[i]的值相差<=k的方案数
f[i]=f[i]*(f[j]+1) j为合法子树,f[j]+1指子树可选可不选
再统计<=k-1的方案数
f[i,k]-f[i,k-1]即为最大与最小值相差k的方案数
const
maxn=4000;
p=19260817;
inf='1030t1.in';
var
e:array[1..maxn,0..maxn]of int64;
v,a,f:array[1..maxn]of int64;
n,k,ans1,ans2,ans:int64;
i:longint;
procedure add(x,y:longint);
begin
inc(e[x,0]);
e[x,e[x,0]]:=y;
end;
procedure init;
var
i,x,y:longint;
begin
readln(n,k);
for i:=1 to n do
read(a[i]);
readln;
for i:=1 to n-1 do
begin
readln(x,y);
add(x,y);
add(y,x);
end;
end;
procedure dfs(x,max,root,kk:longint);
var
i,go,sum:longint;
begin
sum:=1;
for i:=1 to e[x,0] do
begin
go:=e[x,i];
if a[go]>max then continue;
if (a[go]=max)and(go>root) then continue;
if (max-a[go]>kk) then continue;
if v[go]=0 then
begin
v[go]:=1;
dfs(go,max,root,kk);
sum:=sum*(f[go]+1) mod p;
end;
end;
f[x]:=sum;
if sum=1 then
begin
if max-a[x]<=kk then f[x]:=1;
exit;
end;
// f[x]:=sum;
// if sum=1 then f[x]:=0;
end;
begin
// assign(input,inf);reset(input);
init;
for i:=1 to n do
begin
fillchar(f,sizeof(f),0);
fillchar(v,sizeof(v),0);
v[i]:=1;
dfs(i,a[i],i,k);
ans1:=f[i];
if k=0 then ans:=(ans+ans1)mod p;
if k<>0 then
begin
fillchar(f,sizeof(f),0);
fillchar(v,sizeof(v),0);
v[i]:=1;
dfs(i,a[i],i,k-1);
ans2:=f[i];
ans:=(ans+ans1-ans2)mod p;
end;
end;
writeln(ans);
// close(input);
end.