[NOI2009]二叉查找树
CVII.[NOI2009]二叉查找树
首先该树的中序遍历是唯一可以确定的(直接按照数据值排序即可)。
然后,因为权值可以被修改成一切实数,故我们完全可以把权值离散化掉。
于是我们现在可以设置一个DP状态表示:
区间中的所有东西构成了一棵子树,且树中最小权值不小于的最优方案。
然后就枚举根转移即可。转移的时候就可以看作是子树内所有东西被整体提高了一层,所以直接增加(意为区间中的所有数据值之和)即可。同时,如果有当前枚举的根的权值不小于,显然就可以不修改,但是两边儿子的权值就必须比它大;否则则必须修改,两边儿子的权值下限还是(因为根的权值可以被修改成一个略大于的实数)。
则时间复杂度。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m,sum[110],f[110][110][110];
struct dat{
int val,key,lam;
}a[100];
int dfs(int l,int r,int lim){
if(l>r)return 0;
if(f[l][r][lim]!=-1)return f[l][r][lim];
int &now=f[l][r][lim];now=0x3f3f3f3f;
for(int i=l;i<=r;i++){//assume that i is the root in the section [l,r].
if(a[i].key>=lim)now=min(now,dfs(l,i-1,a[i].key)+dfs(i+1,r,a[i].key)+sum[r]-sum[l-1]);//do not modify, the height simply increased by one.
now=min(now,dfs(l,i-1,lim)+dfs(i+1,r,lim)+m+sum[r]-sum[l-1]);//modify i to any real number a little greater than lim.
}
return now;
}
int main(){
scanf("%d%d",&n,&m),memset(f,-1,sizeof(f));
for(int i=1;i<=n;i++)scanf("%d",&a[i].val);
for(int i=1;i<=n;i++)scanf("%d",&a[i].key);
for(int i=1;i<=n;i++)scanf("%d",&a[i].lam);
sort(a+1,a+n+1,[](dat u,dat v){return u.key<v.key;});
for(int i=1;i<=n;i++)a[i].key=i;
sort(a+1,a+n+1,[](dat u,dat v){return u.val<v.val;});
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i].lam;
printf("%d\n",dfs(1,n,1));
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?