2024/9 4-8 笔记

[CCO2017] 接雨滴

题目描述

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

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

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

 *   
 *  *
 *  *
 ** *
*****

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

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

 *   
 *RR*
 *RR*
 **R*
*****

当然了,她也可以这样摆放柱子,这样可以接住 \(6r\) 雨滴。

 *   
 *RR*
 *RR*
**RR*
*****

再举一个例子,如果柱子的高度分别为 \((5,1,5,1,5)\),Lucy 可以接住 \(8r\) 雨滴。

*R*R*
*R*R*
*R*R*
*R*R*
*****

最后一个例子,如果柱子的高度分别为 \((5,1,4,1,5)\),她可以接住 \(9r\) 雨滴。

*RRR*
*R*R*
*R*R*
*R*R*
*****

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

slove

结论:对于某个柱子 x 上方的积水体积,可能产生的所有体积都是合法的。

证明:

首先,形成积水肯定需要两个高柱子,即最高柱和次高柱。我们先放好。接着,我们要插入一个柱子\(x\),考虑\(x\)上方能增加多少积水体积。

1)若我们想让x上方没有积水

我们找到柱子\(y\),使得\(Hy <= Hx\)\(Hy\)最小并且y上方没有积水。
我们再找一个比\(y\)更高的柱子\(z\)
image
https://excalidraw.com/
\(x\)插在\(y\)\(z\)之间且紧贴着\(z\)
image
因为我们找到的 \(y\) 是所有高度不大于 \(x\) 号柱子、且上方没有积水的柱子里最低的那一个,因此 \(z\) 高度一定大于等于 \(x\) (不然找到的就该是 \(z\) 了),于是这么插入不会产生新的积水。

\(y\)存在的情况下,由于有最高峰,所以\(z\)一定存在。如果y不存在,那么不被积水覆盖的柱子都比x高,直接把x放在边界。
image

因此,一定有一种方案使得插入x后总共先不变。

2)设有一个比他高的柱子\(y\),要使得总贡献增加\((a{_y}-a{_x})\)
1.如果y没有被积水覆盖

image
除非\(y\)是最高峰,一定可以插到y的一侧满足总贡献增加\((a{_y}-a{_x})\)

2.如果\(y\)被覆盖了。

找到一个离\(y\)最近的,最低的且没有被积水覆盖的柱子\(z\).
image
我们把\(y\)换为\(x\),贡献变为了\((a{_y}-a{_x})\), 把\(y\)抽出来,按照1)处理即可。

3)如果\(y\)未被插入,从大到小插入就可以。

综上,对于某个柱子 $
x $上方的积水体积,可能产生的所有体积都是合法的。

背包转移,bitset优化。


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);
        }
    }
}
posted @ 2024-09-08 21:56  Dreamers_Seve  阅读(11)  评论(0编辑  收藏  举报