CF754D Fedor and coupons(优先队列)

题目传送门

思路

这道题我刚开始的思路,是按照l为第一关键字,r为第二关键字从小到大排完序以后,二分答案,后来wa掉了,其实就是排完序的结果未必能够连续使用。
因为如果区间非常长的小
比如k=3
1 9
5 6
5 9
6 10
如果是用二分的话5 6是没有办法排掉的
因此我们可以用优先队列,将l从小到大进行遍历,然后将右端点r压入优先队列,将小的先弹出,因为最后的答案一定是所有区间的交集,那么l是所有区间的左端点的最右边那个,右端点就是最左边那个,所以我们遍历左端点,然后保证了当前的端点已经是我们判断的端点最右边那个,当然了,右边的也一定说明最小的那个。
其实这里还有一个疑问,就是如果当前入堆的刚好是要弹出的,那么我们做了一次运算,是不是会有问题,其实答案是不会的,因为,如果当前要弹出的话,我们确保了l比上次还要大,但是r却和上一次一样,因此这个一定不是最大值。

#include<bits/stdc++.h>
using namespace std;

struct node{
	int l,r,id;
}s[2102100];
int ans[2102100];
int n,k;
int ll,rr;
int lans,rans;
int cmp(node x,node y){
	//if(x.l==y.l)return x.r<y.r;
	return x.l<y.l;
}
int check(int mid){
	int lmax=-1e9;
	int rmin=1e9;
	for(int i=1;i<=n-k+1;i++){
		ll=i,rr=i+k-1;
		lmax=-1e9;
		rmin=1e9;
		for(int j=ll;j<=rr;j++){
			lmax=max(lmax,s[j].l);
			rmin=min(rmin,s[j].r);
		}
		if(rmin-lmax+1>=mid)return true;
	}
	return false;
}*//*
int bsearch(int l,int r){
	int mid;
	while(l<r){
		mid=l+r+1>>1;
		if(check(mid)){
			lans=ll;
			rans=rr;
			l=mid;	
		}
		else r=mid-1;
	}
	return l;
}*//*
int main(){
	cin>>n>>k;
	priority_queue<int>q;
	for(int i=1;i<=n;i++){
		int l,r;
		cin>>l>>r;
		s[i]={l,r,i}; 
	}
	sort(s+1,s+1+n,cmp);
	int ans=0;
	int l=1e-9,r=1e9;
	for(int i=1;i<=n;i++){
		q.push(-s[i].r);
		if(q.size()>k)q.pop();
		if(q.size()==k){
			int tot=-q.top();
			tot-=s[i].l-1;
			if(tot>ans){
				ans=tot;
				l=s[i].l,r=-q.top();
			}	
		}
		
	}
	cout<<ans<<endl;
	if(ans==0){
		for(int i=1;i<=k;i++)cout<<i<<" ";
		return 0;
	}
	int tot=0;
	for(int i=1;i<=n;i++){
		if(s[i].l<=l&&s[i].r>=r){
			cout<<s[i].id<<" ";
			tot++;
		}
		if(tot==k)break;
	}
	
}





上一篇:Atcoder 试题选做


下一篇:ubuntu搭建svn、git遇到的问题及解决办法