[贪心]Package Delivery 2022杭电多校第3场 1009

22 篇文章 0 订阅

Little Q likes online shopping very much. In the next 10^9109 days, there will be nn packages delivered to the post office in total. Let's label the next 10^9109 days as day 1, day 2, \dots…, day 10^9109 respectively. For the ii-th package, it will arrive at the post office at day l_ili​, and the deadline to take it back home is day r_iri​, which means Little Q can take it back home at day xx if and only if l_i\leq x\leq r_ili​≤x≤ri​.

Every time Little Q comes to the post office, he can take at most kk packages together back home at the same time. Note that Little Q can go to the post office multiple times during a single day. Please help Little Q determine how to take these nn packages back home such that the number of times he will go to the post office is minimized.

Input

The first line contains a single integer TT (1 \leq T \leq 3\,0001≤T≤3000), the number of test cases. For each test case:

The first line contains two integers nn and kk (1 \leq k\leq n \leq 100\,0001≤k≤n≤100000), denoting the number of packages and the number of packages Little Q can carry at the same time.

Each of the following nn lines contains two integers l_ili​ and r_iri​ (1 \leq l_i\leq r_i \leq 10^91≤li​≤ri​≤109), describing a package.

It is guaranteed that the sum of all nn is at most 1\,000\,0001000000.

Output

For each test case, output a single line containing an integer, denoting the minimum possible number of times that Little Q will go to the post office.

Sample

InputOutput
 
1 
4 2 
1 3 
2 4 
6 7 
4 7
 
2

题意: 给出n个快递的到达时间和最晚取件时间,每次最多拿k个快递,问最少几次取完。

分析: 这是一道贪心题,一开始我的贪心思路是每到k个快递就去取一次,毕竟这k个早晚都要取,保证囤积的快递不超过k个,如果今天有快递过期那么就一次把囤积的快递取光,后来发现这样是不对的,主要是用优先队列维护囤积快递过期时间时,很可能先到的k个到期时间很长,但是还是立马把它们取走了,实际上可以一直拖着,因为后续有过期快递时可以顺便取之前的,比如第一天来了k个很久以后才过期的快递,第二天来了1个当天过期的快递,第三天来了k-1个当天过期的快递,那么按照我之前的贪心思路需要取3次,但是如果换一种贪心思路,也就是拖延症做法,快递到了就是不取,直到今天有快递过期才去取,取完今天过期的还可以顺带捎上几个最近要过期的快递,按照这种做法只需要取2次。

具体做法是对快递到达时间以及过期时间离散化,并维护一个存储过期信息的数组End,表示第i天有End[i]个快递要过期,用一个pair数组存储快递信息,然后对快递按照到达时间排序,之后枚举时间i,同时需要有一个优先队列维护囤积快递的过期时间,如果第i天有快递到达那就加入优先队列q,q中升序存储快递的过期时间,如果当天有快递过期,也就是End[i]非0,那就用若干次把要过期的快递全部取走,如果End[i]不是k的倍数,那么最后一次取的时候还可以捎上一些其它快递,按照贪心的思路肯定捎上最近要过期的快递,取快递时需要弹出优先队列队头,同时更新一下End数组,已经取走的快递就不会对End数组有贡献了。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#define pii pair<int, int>
#define l first
#define r second
using namespace std;

vector<int> alls;
int n, k;
pii a[100005];
int End[200005];//记录该天要过期的包裹数 

int find(int x){
	return lower_bound(alls.begin(), alls.end(), x)-alls.begin()+1;
}

signed main()
{
	int T;
	cin >> T;
	while(T--){
		alls.clear();
		scanf("%d%d", &n, &k);
		for(int i = 1; i <= n; i++){
			scanf("%d%d", &a[i].l, &a[i].r);
			alls.push_back(a[i].l);
			alls.push_back(a[i].r); 
		} 
		sort(alls.begin(), alls.end());
		alls.erase(unique(alls.begin(), alls.end()), alls.end());
		for(int i = 1; i <= alls.size(); i++)
			End[i] = 0;
		int ans = 0;
		for(int i = 1; i <= n; i++){
			a[i].l = find(a[i].l);
			a[i].r = find(a[i].r);
			End[a[i].r]++; 
		}
		sort(a+1, a+n+1);
		int j = 1;
		priority_queue<int, vector<int>, greater<int> > q;//记录到期时间 
		for(int i = 1; i <= alls.size(); i++){
			while(a[j].l == i){
				q.push(a[j].r);
				j++;
			}
			if(End[i]){//当天有即将到期的 
				int t = End[i]/k, mod = End[i]%k;
				ans += t;
				for(int j = 1; j <= End[i]; j++)
					q.pop();
				if(mod){
					ans++;
					int num = min(k-mod, (int)q.size());
					for(int j = 1; j <= num; j++){
						End[q.top()]--;
						q.pop();
					}
				}
			}
		}
		printf("%d\n", ans);
	}
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值