[树形dp] Jzoj P5913 林下风气

Description
里口福因有林下风气,带领全国各地高校掀起了一股AK风,大家都十分痴迷于AK。里口福为了打击大家的自信心,出了一道自以为十分困难的题目。
里口福有一棵树,第i个节点上有点权ai,他的问题就是这棵树中有多少个不同的连通块满足连通块的最大值与最小值之差=k,两个连通块不同当且仅当至少存在一个节点在一个连通块中出现而另一个连通块中没有出现。
痴迷于AK的你马上接下这道题目,在里口福狂妄的笑声中,你切掉这道题的决心更加坚定了,现在就差你的代码了。
 
Input
第一行两个整数n,k,表示树的大小以及题目中的k。
第二行n个整数,第i个整数表示ai。
接下来n-1行,每行两个整数x,y表示树边(x,y)。
Output
一行一个整数,表示答案,答案对19260817取模。
 
Sample Input
5 3
1 2 3 4 5
1 2
1 3
2 4
2 5
Sample Output
4
 
 
Data Constraint
对于30%的数据,n<=22
对于另外20%的数据,树是一条链
对于另外20%的数据,ai只有0和1两种
对于100%的数据,N<=3333,0<=ai<=N,K>=0

 

 

题解

  • 首先,我们知道一个东西,等于k的数量=小于等于k的数量-小于等于k-1的数量
  • 这样的话,其实就好做多了
  • 枚举n个数,为当前dp的最大值,那么走的每一个点与最大值的差都要小于k且大于0
  • 至于统计答案,就是每次搜索数量的乘积,不过每次要加1,因为可以当前不走了也是算一种方案

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #define mo 19260817
 4 #define N 4000
 5 using namespace std;
 6 struct edge {int to,from;} e[N*2];
 7 long long ans1,ans2;
 8 int n,k,cnt,v[N],head[N];
 9 void insert(int x,int y) { e[++cnt].to=y; e[cnt].from=head[x]; head[x]=cnt; }
10 long long dp(int x,int fa,int mx)
11 {
12     long long res=1;
13     for (int i=head[x];i;i=e[i].from)
14         if (v[mx]>=v[e[i].to]&&v[mx]-v[e[i].to]<=k&&e[i].to!=fa&&(v[e[i].to]!=v[mx]||e[i].to>mx))
15             res=res*(dp(e[i].to,x,mx)+1)%mo;
16     return res;
17 }
18 int main()
19 {
20     freopen("lkf.in","r",stdin),freopen("lkf.out","w",stdout);
21     scanf("%d%d",&n,&k);
22     for (int i=1;i<=n;i++) scanf("%d",&v[i]);
23     for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert(x,y),insert(y,x);
24     for (int i=1;i<=n;i++) ans1=(ans1+dp(i,0,i))%mo;
25     if (k!=0)
26     {
27         k--;
28         for (int i=1;i<=n;i++) ans2=(ans2+dp(i,0,i))%mo;
29     }
30     printf("%lld",(ans1-ans2+mo)%mo);
31 }

 

转载于:https://www.cnblogs.com/Comfortable/p/9819116.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值