Description
里口福因有林下风气,带领全国各地高校掀起了一股AK风,大家都十分痴迷于AK。里口福为了打击大家的自信心,出了一道自以为十分困难的题目。
里口福有一棵树,第i个节点上有点权ai,他的问题就是这棵树中有多少个不同的连通块满足连通块的最大值与最小值之差=k,两个连通块不同当且仅当至少存在一个节点在一个连通块中出现而另一个连通块中没有出现。
痴迷于AK的你马上接下这道题目,在里口福狂妄的笑声中,你切掉这道题的决心更加坚定了,现在就差你的代码了。
里口福有一棵树,第i个节点上有点权ai,他的问题就是这棵树中有多少个不同的连通块满足连通块的最大值与最小值之差=k,两个连通块不同当且仅当至少存在一个节点在一个连通块中出现而另一个连通块中没有出现。
痴迷于AK的你马上接下这道题目,在里口福狂妄的笑声中,你切掉这道题的决心更加坚定了,现在就差你的代码了。
Input
第一行两个整数n,k,表示树的大小以及题目中的k。
第二行n个整数,第i个整数表示ai。
接下来n-1行,每行两个整数x,y表示树边(x,y)。
第二行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
对于另外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 }