[CCO 2017]接雨滴(2021/11/19)
接雨雨
原题
题意:
我们有一个宽度为
其中第
我们可以在二维空间的底线上以任意顺序顺次放置柱子,注意不能扔掉任何一个柱子。
如果某个格子水平方向两侧都有柱子阻挡,那么此处就会积水。而地图边界最左与最右没有阻挡,不会产生积水。
重要结论:
对于某个柱子 x 上方的积水体积,可能产生的所有体积都是合法的。
HINT:
考虑在不含 x 的局面插入 x 。
HINT2:
让 x 与某个柱子交换。
证明:
我们最开始先放最高峰与第二高峰(因为她们俩一定不会在上方产生贡献),然后考虑在一个不含
情况一:我们想让 x 号柱子上方没有积水
我们找到在所有高度不大于
我们再找到
因为我们找到的
首先在存在
其次如果不存在
因此,在一个不存在
情况二:设某个比他高的柱子为 y ,目标是使总贡献增加 (a_y-a_x)
-
如果在该局面下,
y 并没有被积水覆盖
除让最高峰作为
考虑
而除了最高峰可以是两侧积水都比她自己低,其他柱子不可能产生这种情况(因为最高峰一定比她更高,如果没被积水覆盖,那她与最高峰之间的积水高度一定是她自己的高度)
-
如果在该局面下,
y 被积水覆盖
那么我们就把
假设
显而易见,
-
如果在该局面下,
y 未被插入
按照从大到小插入的方式就可以规避这种情况。
先处理
因为一个更高的柱子产生贡献不可能依赖于更矮的柱子,所以这种产生贡献的依赖关系图是个有向无环图,并且只会有更低的柱子连向更高的柱子这种边。
我们按照从大到小的顺序插入就不会导致找不到
综上,对于某个柱子
有了这个结论我们就可以开始做了。
对所有柱子与比她高的柱子(除去最高峰)做差,然后进行个背包(注意:对于同一局面,某个柱子只能有一种添加贡献的方法),求出哪些值是可行的。枚举复杂度
518B,简单又好写,跑得飞快。
#include<bits/stdc++.h>
using namespace std;
const int maxN=5e2+5,maxH=5e1+5;
int a[maxN];
bitset<maxN*maxH>dp,tem;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
dp[0]=true;
for(int j=1;j<n;++j)
{
for(int st=j+1;st<n;++st)
{
tem|=(dp<<(a[st]-a[j]));
}
dp|=tem;
}
for(int i=0;i<=25000;++i)
{
if(dp[i])
{
printf("%d ",i);
}
}
}