P3620 [APIO/CTSC2007] 数据备份
这题和 P1792 [国家集训队 种树] 差不多,可以看看我的博客 https://www.cnblogs.com/maburb/p/18664870
题意:有n个点,你要用k根线两两连接,线的长度就是他们的距离,问最小总长度是多少。
一个不可能越过中间一个点去和其他点连接,因为很明显这样距离更长,举个例子,对于a, b, c, d这四个位置来说,a连b+c连d肯定小于a连d加b连c。所以我们只能选相邻的点连接,那么我们把所以两个点直接的连线都拿出来,总共n - 1条线,题意转换为从这些线里选k条,并且任意两条不能相邻。
那么我们贪心的想,优先选最小的,但是这样可能选不够k条,那么我们只能放弃一条线选他两边的两条线来增加线的数量,那么这个贡献是怎么变化的?假设每条线长度为
点击查看代码
void solve() {
int n, k;
std::cin >> n >> k;
std::vector<i64> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::vector<i64> val(n + 1);
std::vector<int> l(n + 1), r(n + 1);
using PII = std::pair<i64, int>;
std::priority_queue<PII, std::vector<PII>, std::greater<PII> > heap;
for (int i = 1; i < n; ++ i) {
l[i] = i - 1;
r[i] = i + 1;
val[i] = a[i] - a[i - 1];
heap.push({val[i], i});
}
val[0] = val[n] = 1e9;
heap.push({val[0], 0});
heap.push({val[n], n});
auto del = [&](int p) -> void {
if (p <= 0 || p >= n) {
return;
}
l[r[p]] = l[p];
r[l[p]] = r[p];
};
i64 ans = 0;
std::vector<int> vis(n + 1);
while (k -- ) {
while (vis[heap.top().second]) {
heap.pop();
}
auto [v, id] = heap.top(); heap.pop();
ans += v;
// std::cout << id << " " << v << "\n";
val[id] = val[l[id]] + val[r[id]] - v;
heap.push({val[id], id});
vis[l[id]] = vis[r[id]] = 1;
del(l[id]); del(r[id]);
}
std::cout << ans << "\n";
}
分类:
刷题
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具