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; }
原文地址:https://www.cnblogs.com/zsben991126/p/10050702.html
时间: 2024-10-16 11:56:52