CF982D 鲨鱼

1 CF982D 鲨鱼

2 题目描述

时间限制 \(1s\) | 空间限制 \(256M\)

长期以来,科学家一直在研究鲨鱼的行为。鲨鱼和其他许多物种一样,有两种行为模式,要么在特定地点附近活动,要么在不同的地点之间做长距离活动。
\(Max\) 是一位年轻的生物学家。在 \(n\) 天的时间里,他固定观察一条鲨鱼,他知道鲨鱼在每一天活动所经过的距离,鲨鱼每天活动的距离都不一样。\(Max\) 现在想知道鲨鱼去过多少个地点。他假设如果鲨鱼每天的行进距离严格小于某个数 \(𝑘\),则鲨鱼没有离开那个地点。如果鲨鱼有一天在移动的距离大于或等于 \(𝑘\),那么鲨鱼那天在不同地点活动。注意鲨鱼有可能连续几天改变地点,也就是说每天移动的距离都大于等于 \(k\)
鲨鱼从一个地点离开后再也不会回来,在连续的 \(n\) 天中鲨鱼有可能每天的移动距离都小于 \(k\),这样我们知道鲨鱼没有离开这个地点。\(Max\) 想找到一个 \(k\) 使得鲨鱼每天活动距离小于 \(k\) 的天数相同。找到使得鲨鱼活动地点最多的 \(k\),如果有好几个类似的 \(k\),输出最小的那个。

3 题解

我们首先研究一个性质:最终我们找到的高度,一定是某个给定高度 \(+1\)。这是因为,如果我们找到的不是某个高度 \(+1\),那么我们可以通过向下调整,调整到离它最近的那个给定高度 \(+1\) 的位置。有了这个性质之后,我们就可以考虑枚举将所有的高度从小到大排序,然后让 \(k\) 随着高度增加慢慢增加。那么我们接下来只需要计算出当前这个高度能产生多少个区间以及最大区间长度和最大区间个数即可。这个东西求出看起来麻烦,但是我们有一个提示:所有 \(a_i\) 都是不同的。也就是说,我们每次提高 \(k\) 的高度后,只会多出一个被包括的数。

这个时候,我们就可以考虑使用并查集维护所有小于 \(k\) 的区间了。如果我们发现,最新的那个出现的数两旁之前都没有数,那么这个数就单独作为一个区间。总区间数 \(cnt+1\),如果最大区间长度 \(maxlen\)\(0\)(之前没有出现过区间),那么将 \(maxlen\) 更新为 \(1\),最大区间个数 \(maxcnt\) 更新为 \(1\)。如果 \(maxlen\)\(1\),那么将 \(maxcnt + 1\)。同时不要忘了给当前位置打上标记。如果最新出现的那个数右边有数,那么我们可以把当前这个点合并到那个并查集中,这里我们用 \(siz\) 数组记录并查集的大小,也就是区间长度。如果我们发现,合并完了之后 \(siz\)\(maxlen\) 大,那么我们就用 \(siz\) 更新 \(maxlen\),并且将 \(maxcnt\) 置为 \(1\)。如果合并完了之后发现 \(siz = maxlen\),那么 \(maxcnt\)\(+1\)。左边同理。

如果新出现的那个数两边都有数,那么我们要把两边的数的祖先合并到当前这个数上(注意一定要这样合并,否则无法串联起左右两个区间)。然后就是照常更新最大值和最大区间个数等即可。这里注意:我们因为合并了两个区间,所以使总区间个数减少了,\(cnt\) 就要 \(-1\),而上面的情况由于我们是直接在区间旁边增加了一个数,区间个数没有增加或者减少。

最后,如果总区间个数等于最大区间个数,说明所有的区间都是最大区间,满足题意。此时如果总区间个数比之前的区间个数要大,那么直接将 \(ans\) 赋为当前高度 \(+1\),如果相同,那么比较 \(ans\) 与当前高度\(+1\) 的大小,\(ans\) 取其中的最小值。

4 代码(空格警告):

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
int n, maxcnt, maxlen, cnt, ans, anscnt;
int fa[N], siz[N];
bool f[N];
struct num
{
    int val, id;
}a[N];
bool cmp(num x, num y)
{
    return x.val < y.val;
}
int find(int x)
{
    if (x == fa[x]) return fa[x];
    return fa[x] = find(fa[x]);
}
void merge(int x, int y)
{
    int fx = find(x), fy = find(y);
    if (fx == fy) return ;
    siz[fy] += siz[fx];
    fa[fx] = fy;
}
int main()
{
    ans = 0x3f3f3f3f;
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i].val, a[i].id = i;
    for (int i = 1; i <= n; i++) fa[i] = i;
    for (int i = 1; i <= n; i++) siz[i] = 1;
    sort(a+1, a+n+1, cmp);
    for (int i = 1; i <= n; i++)
    {
        if (!f[a[i].id-1] && !f[a[i].id+1])
        {
            cnt++;
            f[a[i].id] = 1;
            if (maxlen < 1)
            {
                maxlen = 1;
                maxcnt = 1;
            }
            else if (maxlen == 1) maxcnt++;
        }
        else if (!f[a[i].id-1] && f[a[i].id+1])
        {
            f[a[i].id] = 1;
            merge(a[i].id, a[i].id+1);
            if (siz[find(a[i].id+1)] > maxlen)
            {
                maxlen = siz[find(a[i].id+1)];
                maxcnt = 1;
            }
            else if (siz[find(a[i].id+1)] == maxlen) maxcnt++;
        }
        else if (f[a[i].id-1] && !f[a[i].id+1])
        {
            f[a[i].id] = 1;
            merge(a[i].id, a[i].id-1);
            if (siz[find(a[i].id-1)] > maxlen)
            {
                maxlen = siz[find(a[i].id-1)];
                maxcnt = 1;
            }
            else if (siz[find(a[i].id-1)] == maxlen) maxcnt++;
        }
        else
        {
            cnt--;
            f[a[i].id] = 1;
            merge(a[i].id-1, a[i].id);
            merge(a[i].id+1, a[i].id);
            if (siz[a[i].id] > maxlen)
            {
                maxlen = siz[a[i].id];
                maxcnt = 1;
            }
            else if (siz[a[i].id] == maxlen) maxcnt++;
        }
        if (cnt == maxcnt)
        {
            if (cnt > anscnt)
            {
                anscnt = cnt;
                ans = a[i].val+1;
            }
            else if (cnt == anscnt) ans = min(ans, a[i].val+1);
        }
    }
    cout << ans;
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-02-13 12:04  David24  阅读(172)  评论(0编辑  收藏  举报