题解 CF486D Valid Sets
相当牛逼。
这种找数量的题型,确定树形 没跑了。
首先思考常规树形 ,不难想到设 表示以 为根节点的子树内(包括点 ),最大值是 ,最小值是 的连通子图数量,转移很容易,但是这样时间空间复杂度是 ,而且无论是状态上还是转移上都没有优化的空间。
这时考虑树形 的另一种形式:特殊意义法。
我们从思考每个点对答案做出的贡献,从一个点出发,并规定这个点是联通子图中的最大值,为了不重复,规定若 ,当 时点 更大。
那么我们从每个点出发,设 表示以 为根节点的连通子图个数,转移是显然的:
代码:
#include<bits/stdc++.h> using namespace std; typedef long long LL; LL read() { LL sum=0,flag=1; char c=getchar(); while(c<'0'||c>'9') {if(c=='-') flag=-1; c=getchar();} while(c>='0'&&c<='9') {sum=sum*10+c-'0'; c=getchar();} return sum*flag; } const int N=2100; const LL MOD=1e9+7; int n,d; int a[N]; LL f[N]; vector<int> g[N]; void dfs(int nd,int fa,int id,int w) { f[nd]=1; for(int x:g[nd]) { if(x==fa) continue; if(a[x]>w||(a[x]==w&&x>id)) continue; if(w-a[x]>d) continue; dfs(x,nd,id,w); f[nd]=(f[nd]+f[nd]*f[x]%MOD)%MOD; } } int main() { cin>>d>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<n;i++) { int x,y; cin>>x>>y; g[x].push_back(y); g[y].push_back(x); } LL ans=0; for(int i=1;i<=n;i++) { memset(f,0,sizeof(f)); dfs(i,0,i,a[i]); ans=(ans+f[i])%MOD; } cout<<ans; return 0; } /* */
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效