【问题描述】
出题呢,是要讲究题目背景的的。所以有一个素材库,里面有好多各式各样的题面。但
是不同的题目审核员对题目长度有着执著的要求,每个审核员要求你的题面长度在他的接受范围内。否则题目审核就会不通过。
现在有一个题面素材库,里面共有 n 条素材,第 i 条素材长度为 len(i)。有 m 个审核员,
第 i 个审核员的要求题面长度不小于 L(i),不长于 R(i)。但是所有审核员都会疲劳的,所以每个审核员只会审理一道题。你拿着这 n 道题,请问如何给每道题选择一个审核员,使得最后通过的题目数量尽量多。
【输入】
第一行两个整数 n 和 m,表示有 n 条素材和 m 个审核员。
接下来一行为 n 个用空格隔开的整数,表示 n 条素材的长度。
接下来 m 行里的第 i 行为两个整数 L(i),R(i),表示第 i 个审核员期望的长度不小于 L(i),
不大于 R(i)。
【输出】
一个整数,表示最多可以通过审核几道题目
【输入输出样例 1】
Input
3 4
2 5 6
1 3
2 3
1 7
8 9
Output
2
【数据规模和约定】
共有 3 条素材,长度分别为 2、5、6。可以把长度为 2 的素材送给第一个审核员,长度为 5的送给第三个审核员,长度为 6 不能送给剩下的任何审核员了。
30%的数据 1 <= n, m <= 10
60%的数据 1 <= n, m <= 1000
100%的数据 1 <= n, m <= 100000,1 <= L(i),R(i),len(i) <= 100000,L(i) <= R(i)。
【题解】
这题似乎是个贪心水题。。。就是以右端点对区间进行排序,用小根堆维护区间。实现即每个点枚举区间,取最前面可行区间即可。
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<vector>
#define fp(i,a,b) for(int i=a;i<=b;i++)
#define fq(i,a,b) for(int i=a;i>=b;i--)
#define il inline
#define re register
#define ll long long
using namespace std;
const int N=2e5+5;
struct Point
{
int l,r,type;//type中,0是区间,1是点
bool operator <(const Point & y) const//第一次打符号重载
{
return (l<y.l)||(l==y.l&&type<y.type);//左端点为第一关键字,类型为第二关键字
}
}a[N];
int n,m,ans=0;
priority_queue<int> q;
il int gi()
{
int x=0;
short int t=1;
char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
int main()
{
freopen("bg.in","r",stdin);
freopen("bg.out","w",stdout);
n=gi();m=gi();
fp(i,1,n)
{
int l=gi();
a[i].l=l;a[i].type=1;
}
fp(i,1,m)
{
int l=gi(),r=gi();
a[i+n].l=l;a[i+n].r=r;a[i+n].type=0;
}
sort(a+1,a+1+n+m);//排序
//排序之后,点与点之间按照顺序
//区间和区间之间按照顺序
//如果区间的左端点和点相同则按照区间优先
fp(i,1,n+m)
{
if(!a[i].type) q.push(-a[i].r);//是区间,右端点压入优先队列
else//是点
{
int l=a[i].l;
while(q.size()&&-q.top()<l) q.pop(); //当右侧的端点小于当前的点的位置这个区间就没有用了
if(q.size()) q.pop(),ans++;//如果此时还有区间,则证明右端点要大于这个点,那么,这个区间就选择这个点
}
}
printf("%d
",ans);
fclose(stdin);
fclose(stdout);
return 0;
}