cf1061D 貪心+multiset 好題!
阿新 • • 發佈:2018-12-01
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; }