codeforces 贪心+优先队列_在打CodeForces的过程中发现的一个小模型

本文介绍了一种用于解决特定类型编程竞赛问题的有效模型,并提供了两个实例应用,包括如何通过优化算法将复杂度从指数级降低到线性级。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不久前的Grakn Forces 2020上,我想出了这个方法,我本来以为这个模型不会很常见。然而,今天的CodeForces #679 Div2上,我第二次碰到了可以用这个模型解决的问题,气人的是,这次我却在代码细节上写挂了,最终掉分,愤而决定当作模板记录下来,以免再犯。

问题

个有序对
,对于每个有序对,可以选择将
加入集合
或将
加入集合
,试最小化
。(规定

算法

首先注意到对于

,如果在
的同时有
,那么就可以舍弃
。于是可以将有序对以
为第一关键词、
为第二关键词排序,这样可以保证
是随
单调不减的:

显然,

应该随
单调减。如何保证呢?注意到最后一个有序对肯定要保留,所以我们只需要从后往前遍历,划掉破坏
单调性的元素即可:

当然,在编程中,删除数组中的元素还是太浪费时间了,我们转而把无需删除的有序对加入一个新的数组。只不过,因为我们是从后往前遍历,这样会导致顺序颠倒过来。

这时我们发现,如果我们选了某个

,那么可以无代价地选择它
下方的所有
;如果我们选了某个
,那么可以无代价地选择它
上方的所有
。相当于,我们只需要选择左边的
开头和右边的结尾,而且它们应该是相邻的:

46c73030bd56a0d981549174051dbd6d.png

这样一来,我们一共就只有

种选法了(
为新数组的长度),把原来的指数级问题降成了线性。

代码

int minsum(vector<pair<int, int>> &V)
{
    if (V.empty())
        return 0;
    sort(V.begin(), V.end());
    vector<pair<int, int>> U{V[V.size() - 1]};
    for (int i = V.size() - 2; i >= 0; --i)
        if (V[i].second > U[U.size() - 1].second)
            U.push_back(V[i]);
    int mi = min(U[0].first, U[U.size() - 1].second);
    for (int i = 0; i < U.size() - 1; ++i)
        mi = min(mi, U[i].second + U[i + 1].first);
    return mi;
}

例题

CF1408D:通过计算,可求得每个强盗向上躲过探照灯需走

格,向右躲过探照灯需走
格,记为
。现在要让所有强盗向上、向右各走若干格躲过所有探照灯,也即选若干个
求最大值,选剩余的
求最大值,将这两个最大值的和最小化。这完美符合刚刚那个模型
(当然,因为这模型就是从这个题来的-w-)

CF1435C:我们可以得到

个数,每组各选择一个,让选择的数的极差最小。可以固定其中一组,对于这组数中的每一个
,都把其余各组中最大的
的数和最小的
的数找出来,分别求它们与
的差(如果没有满足某个条件的数,记对应的差为
INF)。这相当于是向左扩展向右扩展。然后套模型。这样我们算出了选固定组每一个数时的最小极差,求一个最小值即可。
### 回答1: 我可以分享一种有效的训练计划,以达到codeforces橙名。首先,建立一个长期的训练计划,每周至少完成3-4个题目,把每个题目的解题过程都认真的思考一遍,确保理解每一步的思路。建议每隔一段时间,做一次综合练习,以更好地检验自己的知识水平。此外,参加竞赛也可以加深对算法的理解,从而提升解题能力。 ### 回答2: 想要在Codeforces达到橙名的水平,需要进行系统性的训练,并掌握一定的算法编程技巧。以下是一个可能的训练计划: 1. 学习基础知识:首先,建议你系统地学习计算机科学的基础知识,包括据结构算法。这可以帮助你理解不同问题的解决方案,并优化代码的执行效率。 2. 解决题目:开始刷题是锻炼算法编码能力的关键。选择一些简单的题目,如Codeforces的Div2 A、B级题目,按难度逐渐增加。通过不断解决题目,你将熟悉各种算法,并提高编写清晰、高效代码的能力。 3. 学习算法:学习掌握一些常用算法,如贪心、动态规划、图论等。理解算法原理,分析其时间空间复杂度,并通过练习将其应用于具体的问题。 4. 参加比赛:参加Codeforces的比赛是衡量自己水平的好方法。开始参加Div2级别的比赛,并争取在中等难度的题目上取得好成绩。逐渐挑战3级、4级比赛,尽量更强的选手竞争,以提高自己的水平。 5. 反思学习:每次比赛后,对自己的解题过程进行反思总结。分析解错的原因,学习其他参赛选手的思考方式技巧。通过学习他人的优秀代码解题思路,不断提升自己的编码能力。 6. 练习编码技巧:除了算法,熟练掌握编码技巧也非常重要。学习并应用一些常用的据结构STL库,如数组、链表、栈、队列等。多写一些小项目或练习题,锻炼自己的编码能力。 7. 时间管理:合理安排学习练习的时间。每天保持一定时间的刷题学习,坚持养成好的学习习惯。同时,在比赛中也要控制好时间,并尽量在限定时间内完成题目。 总之,达到Codeforces橙名的水平需要长期的训练不断的学习。通过刷题、学习算法编码技巧、参加比赛以及反思总结,你可以逐渐提升自己的水平,并取得理想的成绩。记住,坚持持续学习是达到目标的关键。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值