NOIP2018複習 A(樹形DP)

2021-08-30 21:41:01 字數 2565 閱讀 3206

時間限制: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 31 2 3 4 5

1 21 3

2 42 5

輸出樣例複製

說明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.

NOIP2018 賽道修建(樹形dp 二分)

弱雞萌新2018年難忘的騙分之旅 花了2個小時騙分2333 從n個點構成的的樹中取出m條邊不重複路徑,使得最小的路徑最長 由於沒有乙個確定的限制且問題具有單調性,首先肯定想到二分答案,設該數為x,那麼需要找出長度大於等於x的路徑條數 對於乙個子樹i,考慮它的貢獻,分為兩種 i子樹中選一條或兩條鏈,使...

NOIP2018複習 射擊(堆 貪心)

時間限制 2000ms 記憶體限制 65536kb 題目描述 有問題,找副連,無聊的時候當然也可以找他啦。小w找到了他的叔叔 東廠廠長 宇宙超級無敵老ws yy。他們叔侄兩個商量之後決定用彈弓打破社群裡的一些窗戶,但是彈弓每秒只能徹底打破一扇窗戶。而且如果某戶窗戶的主人回來了的話,他們就不能進行破壞...

NOIP2018 保衛王國(動態DP)

求最小權值點覆蓋。m mm次詢問,每次給出兩個點,分別要求每個點必須選或必須不選,輸出每次的最小權值覆蓋或者無解輸出 1 1 1強制選或者不選可以看做修改權值為 pm infin 那麼就是這道板題了。include using namespace std typedef long long ll t...