[CCO2017] 接雨滴

晚上,夜黑风高,大雨疯狂地从天而降。

Lucy 想要接住一些雨滴,但她只有有限的工具。她有一套不同高度的柱子来接住雨滴。每根柱子的高度为整数,宽度为 1。她排列好柱子之后,就会用其他器具夹紧柱子,来让雨滴顺利地储存在柱子的间隙里。你可以认为雨滴的数量是无限的。

举个例子,如果 Lucy 有高度分别为 (1,5,2,1,4) 的五根柱子,她可以这样排列柱子。

 *   
 *rr*
 *rr*
 **r*
*****

这样会接住 5r 雨滴(r 代表 1 个单位的雨滴)。

为了方便表述,我们定义 r 为雨滴的单位。

Lucy 有 nn 个高度为 h1,h2,...,hn 的柱子。她想知道,在所有可能的摆放方案中,所有可能的雨滴量(以 r 为单位)是多少。(具体可看样例解释)

Sol:

考虑结论,对于某个柱子 x 上方的积水体积,可能产生的所有体积都是合法的。证明考虑从大到小插入。

先考虑没有积水的情况,找到一个高度小于 hx 的 没有积水的柱子 y,再找到高度大于 y 的没有积水的柱子 z,把 x 插入 zy 的一侧。

有积水的情况,假设我们要让它积出 hyhx 的水,或者说使得当前的总答案增加 hyhx (注意 hy 不能是最大值,否则无法产生这种情况)。若 y 上没有积水,直接把 x 插到 y 和最大值之间,否则用 x 替换 y,并把 y 用没有积水的情况处理,这样答案增加的也是 hyhx

直接跑背包,用 bitset 优化即可。

#include <bits/stdc++.h>

using namespace std;

const int N = 505;

bitset<N * 50> f, ans;
int n, a[N];

inline int read() {
	register int s = 0; register char ch = getchar();
	while (!isdigit(ch)) ch = getchar();
	while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
	return s; 
}

int main() {
	n = read();
	for (int i = 1; i <= n; ++i) a[i] = read();
	sort(a + 1, a + n + 1); ans[0] = 1;
	for (int i = 1; i < n; ++i) {
		for (int j = i + 1; j < n; ++j)
			f |= ans << (a[j] - a[i]);
		ans |= f;
	}
	for (int i = 0; i < N * 50; ++i)
		if (ans[i]) printf("%d ", i);
	return 0;
}
posted @   Smallbasic  阅读(60)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示