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
Input | Output |
---|---|
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;
}