1. 程式人生 > >cf1061D 貪心+multiset 好題!

cf1061D 貪心+multiset 好題!

cf上的思維題真好!

本題是在模擬的基礎上貪心即可:將n段時間按照左端點(右端點為第二關鍵字)從小到大排序,然後遍歷每一個時間段。

對於每一個時間段【li,ri】,先找到multiset中最靠近li但在li左側的r,

如果沒有這樣的r,即【li,ri】是當前最靠左的,那就需要新加一臺電視機,然後把ri加入multiset

如果找到這樣的r,那就進行一次判斷,如果從r到li等待時間中浪費的錢大於等於新加一臺電視的錢,那就新加一臺電視,把ri加入multiset

否則就接著r往下看,那就把r從multiset中刪掉,然後把新的ri加入multiset中,其實是按照時間線模擬即可!

另外可以把所有的觀看時間提取出來直接求和,兩個1e9+7會爆int!

#include<bits/stdc++.h> 
using namespace std;
const int N=100010 ,mod=1e9+7;
int n,ans,x,y;
struct node{
    int x,y;
    bool operator <(const node&A)const{
        return x == A.x ? y < A.y : x < A.x;
    }
}a[N];
multiset<int>s;
multiset<int>::iterator it;
int main(){
    scanf(
"%d%d%d",&n,&x,&y); for(int i=1;i<=n;i++){ scanf("%d%d",&a[i].x,&a[i].y); ans = (ans + 1ll * y * (a[i].y - a[i].x) %mod)%mod; }//先把必須要看的地方加上去 sort(a+1,a+n+1);//時間按照左端點排序 for(int i=1;i<=n;i++){ it = s.lower_bound(a[i].x);//找第一個不小於x的時間右端點 if
(it==s.begin() || 1ll*(a[i].x-*(--it)) * y >= x){//如果所有時間的右端點都大於x,或者新加一臺電視比等待的費用低,那麼新加一臺電視 ans=(ans+x)%mod; s.insert(a[i].y);//新加一臺電視機 }else{ ans=(ans+1ll*(a[i].x-*it) * y%mod)%mod;//不加電視機繼續等待 s.erase(it);//把 上一個時間點刪掉 s.insert(a[i].y); } } printf("%d\n",ans); return 0; }