AtCoder Beginner Contest 271 C Manga(贪心 set 注意事项)

16 篇文章 0 订阅
4 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题意:

给定一个数组,你可以对数组进行 若干次操作,每次操作可以 删除两个数字并添加一个数,求 1 2 3 连续自然数的最后一个值最大

思路:

先将输入的元素 放入 set < int > tr 中进行去重,显然 去重后的元素个数为 tr.size()

贪心策略
从前往后遍历每个 i ∈ [1, +∞),如果 itr 中存在,则 直接将其删除

如果不存在

  • 优先删除 “盈余元素”,总元素个数为 n去重后元素个数为 tr.size(),则 盈余元素数量为 cnt = n - tr.size()。这里删的时候无需真正删除,只需要 每次将 cnttr 减少对应次数即可(当 cnt >= 2对应 cnt -= 2,此时 tr 无需删除元素。当 cnt == 1对应 cnt -= 1tr 中最大的元素删除)。

  • 当 “盈余元素” 删除完成后,即 cnt == 0,判断 tr 中的元素是否大于等于 2,如果 ,则 删除 tr 中最大的两个元素,如果 不是,则表示 无法继续遍历当前 i,则直接 输出 i - 1

(上面的 删除 操作 每次都要保证恰好删除 2 个元素

使用 set 时 注意事项:

set 不仅能 以 元素值 作为 erase 时的索引,还可以以 迭代器 作为 索引,这点很强大,本题中两者都用到了。

题中涉及到了 set 中最大的两个元素删除,对应到代码上就是:

//前提是保证 tr.size() >= 2
auto pp = tr.end(); --pp; tr.erase(pp);
auto qq = tr.end(); --qq; tr.erase(qq);

而不能写成下面的形式,输入数据时会报错,即 不能将一个迭代器连续递减两次

//前提是保证 tr.size() >= 2
auto pp = tr.end(); --pp; tr.erase(pp);
--pp; tr.erase(pp);

时间复杂度:

O ( n l o g n ) O(nlogn) O(nlogn)

代码:

#include <bits/stdc++.h>

using namespace std;
//#define int long long
//#define map unordered_map
const int N = 3e5 + 10;
int a[N];

inline void solve()
{
    int n; scanf("%d", &n);
    set<int> tr;
    for (int i = 1; i <= n; ++i)
    {
        scanf("%d", &a[i]);
        tr.insert(a[i]);
    }
    int cnt = n - tr.size();
    for (int i = 1; ; ++i)
    {
        auto p = tr.find(i);
        if (p == tr.end())
        {
            if (cnt >= 2) {
                cnt -= 2;
            }
            else if (cnt == 1 && tr.size() >= 1) {
                --cnt;
                auto pp = tr.end(); --pp; tr.erase(pp);
            }
            else if (cnt == 0 && tr.size() >= 2) {
                auto pp = tr.end(); --pp; tr.erase(pp);
                auto qq = tr.end(); --qq; tr.erase(qq);
            }
            else {
                printf("%d\n", i - 1);
                return;
            }
        }
        else
        {
            tr.erase(p);
        }
    }
}

signed main()
{
    //	ios::sync_with_stdio(false);
    //	cin.tie(nullptr), cout.tie(nullptr);

    int _ = 1; //cin >> _;

    while (_--)
    {
        solve();
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值