【Nowcoder】牛客小白月赛26 H 保卫家园 | 贪心、扫描线

emmm…考试周一天一套小白月赛保持手感…

别问为什么,怕被太难的题卡的挂科…

本来不想写什么题解,不过这题确实有妙处,就记录一下吧

题目大意:

为了抵御深渊的蔓延,被深渊毁掉家园的人们组建法兰不死队来镇压深渊。已知法兰不死队的最大编制为 k k k,即队伍最多能有 k k k人。有 n n n个人想加入不死队,他们每人都有一个期望入伍时间 s s s和退役时间 t t t。入伍时间表示这个人如果要入伍的话只能在 s s s时刻入伍。退役时间代表这个人可以在t时刻后退伍。因为战况严峻,所以队伍必须一直保持达到最大编制的状态。即队伍达到最大编制时候,队伍里有人可以退役的话,如果没有人来接替这个人的位置就不能退役。问最少有多少人没有进入法兰不死队的经历。
注:同一时刻,允许多个人一起入伍或者退伍,退伍时间要严格大于 t t t
该人是否入伍是你来决定的 即就算没达到最多编制人数 k k k,到了某人的入伍时间,你可以选择不让他入伍

题目思路:

按照题解所说,可以抽象一下:

选出最多的线段,使的数轴上的每个点被线段覆盖不超过k次

可以把线段覆盖想成区间覆盖问题,当前点被哪些线段覆盖到。之后,可以把以该点作为起点的线段放进到扫描线组成的集合里,但是放入的过程中要考虑一下,如果当前点覆盖超过k次了,应该让哪个线段出去,贪心的考虑,一定会让结束时间大的先出去,因为会减少后面空间的浪费,既然出去了,那么这个就不会入伍了,也就可以记录答案了。

贪心的好题(G)

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17+7;
const ll maxn = 1e6+700;
const ll mod= 1e4+7;
const double PI = acos(-1);
template<typename T>inline void read(T &a){
    
    char c=getchar();T x=0,f=1;while(!isdigit(c)){
    
    if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
    
    x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
multiset<ll>s;
vector<int>v[maxn];
int main(){
    
    
	read(n);read(m);
	for(int i=1;i<=n;i++){
    
    
		int x,y;read(x);read(y);
		v[x].push_back(y);
	}
	int ans = 0;
	for(int i=1;i<=1000000;i++){
    
    
		while(s.size()&&*s.begin() < i) s.erase(s.begin());
		for(int x:v[i]){
    
    
			if(s.size() < m) s.insert(x);
			else{
    
    
				ans ++;
				s.insert(x);
				s.erase(--s.end());
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}
/***
5 2
19186 25985
51782 55585
25373 58921
59901 64624
43221 67137
***/

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/111935364