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条,那么我们只能放弃一条线选他两边的两条线来增加线的数量,那么这个贡献是怎么变化的?假设每条线长度为ai, 我们一开始选了i, 贡献加ai,然后不选第i条选i-1和i+1,那么贡献是减去i的长度加上两边的长度,就是ai1+ai+1+ai,我们在选择第i条线后用这个值替换它成为一个新的点,那么以后选到这个点就相当于进行了这个操作。

点击查看代码
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";
}
posted @   maburb  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示