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;
}

猜你喜欢

转载自www.cnblogs.com/zsben991126/p/10050702.html