【NOIP2018复习】A(树形DP)

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.

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值