1. 程式人生 > >Codeforces Round #523 (Div. 2) D. TV Shows(multiset+思維)

Codeforces Round #523 (Div. 2) D. TV Shows(multiset+思維)

題目連結:

D. TV Shows

 

題意:

有 n 個電視節目,播放的時間區間為 [li,ri] 。同一時間,不同的節目不能在同一臺電視上播放。一個節目必須完整的在一臺電視上播放完。現在租一臺電視需要先付 x 塊錢,之後每分鐘要付 y 塊錢,即租一臺電視從時間區間 [a,b] 需要付 x + (b-a)*y 塊錢。問看完所有的節目至少需要多少錢。

 

思路:

把所有節目按開始時間升序排序,若開始時間相同,按結束時間升序排序。排序後依次遍歷所有節目,對於節目 i,去找之前的節目中結束時間小於節目 i 的開始時間的,且離的最近的,若兩者的時間差*y<=x,那麼兩者可以合併(即在同一電視上播放),否則,需要新租一個電視。

如何找之前的節目中結束時間小於節目 i 的開始時間的,且離的最近的?首先想到二分查詢,但結束時間並不是有序的,因此想到set(會自動排序)。但本題set不行,因為set會自動去重,這會導致錯誤答案。因此使用multiset,它與set的唯一區別就是不會自動去重。

關於思路的一些證明:

1. 所有節目必須先按開始時間升序排序,不能先按結束時間升序排序:

例子:

————    ——————

                           ——

2. 如下那種選擇更優?(假設都是可以合併的)

            ——           ——                     |                    ——         ————————

——————    ——————        |        ——————        ——

其實這兩種情況是一樣的,即間隔之和相同,可自己畫圖試試。

3. 如下那種選擇更優?

    ————               ———— (不能合併)      |            ————         ———————(可以合併)

——————     —————— (可以合併)    |        ——————         ———— (可以合併)

這其實和2同理,因為兩者的間隔之和相同,所以後者相當於前者兩個都合併了,所以後者多付的費用肯定大於前者。

 

Code:

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int MAX = 1e5+10;
const ll mod = 1e9+7;

struct Point{
    ll l,r;
    //定義 < ,用於lower_bound的排序
    bool operator < (const Point &a) const {
        if(r==a.r){
            return l<a.l;
        }
        return r<a.r;
    }
};

int n;
ll x,y;
Point op[MAX];
multiset<Point>s;

bool cmp(Point p,Point q){
    if(p.l==q.l){
        return p.r<q.r;
    }
    return p.l<q.l;
}

int main()
{
    scanf("%d%lld%lld",&n,&x,&y);
    for(int i=0;i<n;i++){
        scanf("%lld%lld",&op[i].l,&op[i].r);
    }
    sort(op,op+n,cmp);
    multiset<Point>::iterator pos;
    for(int i=0;i<n;i++){
       //w.l需要<=0,這樣pos--才是我們想要的結果
       Point w = Point{0,op[i].l};
       pos = s.lower_bound(w);
       if(pos==s.begin()){
          s.insert(op[i]);
       }
       else{
          pos--;
          Point tmp = *pos;
          if((op[i].l-tmp.r)*y>x){
             s.insert(op[i]);
          }
          else{
             tmp.r = op[i].r;
             s.erase(pos);
             s.insert(tmp);
          }
       }
    }
    ll ans=0;
    for(pos=s.begin();pos!=s.end();pos++){
       Point now = *pos;
       ans = (ans+x+(now.r-now.l)*y%mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}