CF486D Valid Sets

题目描述:

给定 n 个点的树,点有点权,求满足最大点权与最小点权之差小于等于 d 的连通子图数目。答案对 109+7 取模。

数据范围:

1d2000,1n2000

1ai2000

1u,vn

思路:

根据我们以往的做题经验,因为要求选出的是一个连通子图,则我们考虑以一些点为根然后顺着根往下选一些边,这样这个子图一定是联通的。

关键是要以哪些点为根?如果以每个点为根的话,很明显会有很多重复的情况,而且不好去重。所以我们并不知道以哪些点为根。

但是!题目中还有一个限制:要求 mxmnd 所以我们不妨钦定一个点为整个联通子图中的最大值,然后以这个点为根,令根节点的值为 art

这样做我们就不用枚举最大最小值了,直接判断是否满足 artaud

这个题目还有一个注意点:他有可能有相同的点权,所以会造成重复的统计。所以考虑钦定只有编号小于 rt 的点才会被统计,这样就可以保证不重不漏。

#include<bits/stdc++.h> using namespace std; #define int long long const int maxn=2005; const int mod=1e9+7; int d,n; int a[maxn]; vector<int>G[maxn]; int dp[maxn]; bool check(int u,int v){ return a[u]>a[v]||(a[u]==a[v]&&u>v); } void dfs(int u,int f,int p){ dp[u]=1; for(int v:G[u]){ if(v==f)continue; if(!check(p,v)||a[p]-a[v]>d)continue; dfs(v,u,p); dp[u]=(dp[u]*(dp[v]+1))%mod; } } signed main(){ cin>>d>>n; for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<n;i++){ int u,v; cin>>u>>v; G[u].push_back(v); G[v].push_back(u); } int ans=0; for(int i=1;i<=n;i++){ dfs(i,0,i); ans=(ans+dp[i])%mod; } cout<<ans<<endl; return 0; }

__EOF__

本文作者Candycar
本文链接https://www.cnblogs.com/Candycar/p/17834757.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Candycar  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示