取包裹(对线段贪心 set+lower_bound)

LINK

题目

在这里插入图片描述

大致题意

有n件包裹,每次可以取k件。给出每件包裹入库时间和最晚取走时间。(入库当天和最晚取走当天都可以取快递)问:最少几次可以将所有包裹取出。

思路

贪心。最小的r rr一定要有一次把它取出来,所以每次在最小r rr当天取出包裹即最优。
r rr从小到大排序,遍历,每次都对最小的r rr进行处理。
如果当前l ll小于等于确定去快递点的时间r rr时,就和离l ll最进时间点r rr一起取走,此时确定去快递点的时间r rr拿包裹的件数加一,若此时那确定去快递点的时间r rr拿满了,说明不能之后的包裹无法在此时刻r rr拿,即删除此r rr
如果当前l ll大于所有已存的确定去快递点的时间r rr就当前r rr时间时拿一次(a n s + + ans++ans++),并且记录此时刻取包裹件数为1。
(大牛思路)

代码

#include<bits/stdc++.h>
using namespace std;
//#define ll long long
#define int long long
const int N = 1e5+10;
const double eps=1e-8;
struct node{//记录r最小 
	int l;int r;
	bool operator <(const node &a)const{
		if(r!=a.r) return r<a.r; 
		return l<a.l ;
	}
}ar[N];
map<int,int>mp;
set<int>se;
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int t,ans,n,k;cin>>t;
	while(t--){
		cin>>n>>k;
		ans=0;mp.clear();se.clear();
		for(int i=0,l,r;i<n;i++){
			cin>>ar[i].l>>ar[i].r;
		}
		if(k==1){
			cout<<n<<endl;continue;
		}
		sort(ar,ar+n);//r从小到大 
		for(int i=0;i<n;i++){//r从小到大 遍历 
			auto pos=se.lower_bound(ar[i].l );
			//判断此包裹是否可以和前面某次一起取走 
			if(pos==se.end()){//无法一起取走
				mp[ar[i].r ]=1;//此时刻拿一次包裹,包裹容量为1 
				se.insert(ar[i].r );  
				ans++;//取快递点次数加一
			}else{//可以一起取走 
				int x=*pos; 
				if(++mp[x]==k)se.erase(x);//增加一件,若包裹容量满了则删除 
			}
		} 
		cout<<ans<<endl;
	} 
	return 0;
}

版权声明:本文为lalala625原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。