彩彩在视频网站上拥有N个粉丝,并且发布了M个视频,编号为0,1,…,M-1 。粉丝会为编号连续的视频点赞,其中第 i 个粉丝选择为 (表示大于等于 并且严格小于 的整数范围)的视频点赞。该网站对视频质量有两个评价指标 x和 y 分别表示:
最小的整数 ,x表示从作者的N个粉丝中 可以选出 x 个粉丝,使得全部的视频都被选中的粉丝点赞过;
最小的整数 ,表示从作者的N个粉丝中 任意选出y 个粉丝,使得全部的视频都被选中的粉丝点赞过。
现在彩彩想要计算 x 和 y,以此来判断自己的视频质量。可是彩彩不会算,因此把任务交给了作为彩黑警察的你。
解题思路:
x: 用贪心思想,从0开始每次选取区间跨度最大的,那么得到的区间总数就是x
y: 鸽巢原理,如果有一个视频只有一个粉丝点赞,那么y就等于n,实际上就是求所有视频中,其被多少个区间覆盖,这个可以根据t1-t2得到。统计最小的(t1-t2),记为p。然后答案就是n+1-p;
int t1 = upper_bound(a.begin(),a.end(),c[i])-a.begin();
int t2 = lower_bound(b.begin(),b.end(),c[i])-b.begin();
易错点,由于M的值特别大,超出了1e9,所以不能遍历所有视频,可以只选区间的左右端点去遍历,但是这时候又会遇到一种情况,如图下所示。s5端内的视频就不会遍历到了,解决办法是加上区间左右端点再扩充一个视频就好了。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
ll l,r;
node(ll a,ll b):l(a),r(b){}
};
bool compare(node n1,node n2){
if(n1.l == n2.l){
return n1.r < n2.r;
}
return n1.l < n2.l;
}
int main() {
//freopen("in.txt", "r", stdin);
//freopen("in1.txt", "r", stdin);
int n;
ll m;
cin>>n>>m;
vector<node>v;
vector<ll>a,b,c,d;
for(int i = 0;i<n;i++){
ll l,r;
cin>>l>>r;
a.push_back(l);
b.push_back(r-1);
c.push_back(l);
c.push_back(r-1);
if(l>0){
c.push_back(l-1);
}
if(r<m){
c.push_back(r);
}
v.push_back(node(l,r));
}
sort(a.begin(),a.end());
sort(b.begin(),b.end());
sort(v.begin(),v.end(),compare);
int res = 1;
ll cur_l = 0,cur_r = -1;
int i = 0;
while(i<n && v[i].l == cur_l){
cur_r = max(cur_r,v[i].r);
i++;
}
for(int j = i;j<n && cur_r!=m;j++){
if(v[j].l<=cur_r && v[j].r > cur_r){
res++;
ll tmp_r = cur_r;
while(j<n && v[j].l <= tmp_r){
cur_r = max(cur_r,v[j].r);
j++;
}
j--;
}
}
int x = res;
res = 2e5+3;
for(i = 0;i<c.size();i++){
int t1 = upper_bound(a.begin(),a.end(),c[i])-a.begin();
int t2 = lower_bound(b.begin(),b.end(),c[i])-b.begin();
res = min(res,t1-t2);
}
int y = n+1-res;
cout<<x<<" "<<y;
return 0;
}