【NOIP2018複習】A(樹形DP)
阿新 • • 發佈:2018-12-19
A
時間限制: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.