CF1061D 电视节目

1 CF1061D 电视节目

2 题目描述

\(𝑛\) 个你想看的电视节目。假设整个时间被分成相等的部分,称为“分钟”。第 \(𝑖\) 个节目是从 \(𝑙_𝑖\)\(𝑟_𝑖\) 分钟,时间包括 \(𝑙_𝑖\)\(𝑟_𝑖\)

你需要一台电视来看一个电视节目,你不能在同一台电视上同时看两个电视节目,所以有时候你可能需要多台电视。例如,如果时间段 \([𝑙_𝑖,𝑟_𝑖]\)\([𝑙_𝑗,𝑟_𝑗]\) 重叠,那么节目 \(𝑖\)\(𝑗\) 不能同时在一台电视上观看。

一旦你开始在某台电视上看节目,就不可能“转移”到另一台电视上(因为这太分散注意力了),也不可能在同一台电视上看另一个节目,必须要等到当前的节目结束。

你附近有一家电视出租店,租一台电视需要 \(𝑥\) 卢比,每多放一分钟就要多收取 \(𝑦\) 卢比的费用,注意 (\(y\)<\(x\))。因此,为了租一台电视的时段 \([𝑎;𝑏]\),你需要支付 \(𝑥+𝑦⋅(𝑏-𝑎)\)

你可以假设,租电视机和还电视机不需要任何时间,也不会分散看其他电视节目的注意力。 找到查看所有节目的最小可能成本。由于这个值可能特别大,输出结果对10^9+7取模的值。

3 题解

我们考虑到,一个节目能在两种情况下被观看:新租一台电视播放或者用之前租的且当前没有在播节目的电视播放。我们只需要在这两种情况中取最优即可。我们观察发现,第一种的花费为定值:\(x + (r_i - l_i) * y\)。而第二种的最优情况为使用播放的节目结束时间最晚的电视来播放当前节目。假设找到的电视最后播放的节目为第 \(j\) 个节目,那么第二种情况的花费为:\(y * (r_i - r_j)\)。对于每一个节目,我们只需要对这两种情况的值取 \(min\) 累加到答案中即可。

这时我们有一个问题:如果我们把播放节目结束时间最晚的电视用来播放当前节目,是不是可能没有让其他电视播放的情况要更次一点?这个问题实际上是不存在的,这是因为,每个电视等待 \(1\) 分钟所多出来的花费 \(y\) 都是相同的。由于所有的节目之间的间隔,等待时间是一样的,所以这个电视之前播放过的节目数并不影响结果。

根据上述贪心结论,我们可以很容易想到使用优先队列把所有电视结束播放的时间进行排序。每次将队头的时间取出进行计算即可。但是,我们发现这时我们无法保证我们找到的时间比当前节目的开始时间要早,所以我们要使用 \(multiset\) 进行计算。

4 代码(空格警告):

#include <iostream>
#include <set>
#include <algorithm>
using namespace std;
const int N = 1e5+10;
const int mod = 1e9+7;
#define int long long
int n, x, y, ans, cnt;
struct seg
{
    int l, r;
}a[N];
multiset<int> q;
multiset<int>::iterator f;
bool cmp(seg ax, seg ay)
{
    if (ax.l == ay.l) return ax.r < ay.r;
    return ax.l < ay.l;
}
signed main()
{
    cin >> n >> x >> y;
    for (int i = 1; i <= n; i++) cin >> a[i].l >> a[i].r;
    sort(a+1, a+n+1, cmp);
    for (int i = 1; i <= n; i++)
    {
        f = q.lower_bound(a[i].l);
        if (f == q.begin() || x <= y * (a[i].l - *(--f)))
        {
            ans = (ans + (x + y * (a[i].r - a[i].l) % mod) % mod) % mod;
        }
        else
        {
            ans = (ans + (y * (a[i].r - *f) % mod) % mod) % mod;
            q.erase(f);
        }
        q.insert(a[i].r);
    }
    cout << ans;
    return 0;
}

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

posted @ 2021-02-05 16:15  David24  阅读(47)  评论(0编辑  收藏  举报