出题

【问题描述】

出题呢,是要讲究题目背景的的。所以有一个素材库,里面有好多各式各样的题面。但
是不同的题目审核员对题目长度有着执著的要求,每个审核员要求你的题面长度在他的接受范围内。否则题目审核就会不通过。
现在有一个题面素材库,里面共有 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\n",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值