[EOJ]2019 ECNU XCPC March Selection #1 F
题意:数轴上有n个点,m条线段,选出尽量多的线段,使每条线段都能独立地占有至少一个点(不可公用同一个点)。
线段覆盖问题,按右端点升序,右端点相同时左端点降序排序,画图可以看出前边的线段应该尽量用前边的点,把点排序,依此对每条线段二分查找可以用的点。
(考场上开始没想清楚,用左端点做了第一关键字,后来好好画图很容易看出来应该用右端点做第一关键字)
比较典型的一道题。
#include<bits/stdc++.h> using namespace std; typedef long long LL ; #define rep(i,n) for(int i=1;i<=n;i++) #define pb push_back #define st first #define nd second #define mp make_pair #define pii pair<int ,int > const int N = 2e4+7; const int MX = 1e9+7; int t[N],n,m,tag[N]; pii a[N]; int cmp(pii a,pii b){ if(a.nd!=b.nd)return a.nd<b.nd; return a.st>b.st; } int find(int x){ int l=1,r=n,ans=n+1; while(l<=r){ int mid=(l+r)/2; if(t[mid]>=x){ ans=mid; r=mid-1; } else l=mid+1; } return ans; } int main(){ scanf("%d%d",&n,&m); rep(i,n)scanf("%d",&t[i]); rep(i,m)scanf("%d%d",&a[i].st,&a[i].nd); sort(t+1,t+1+n); sort(a+1,a+1+m,cmp); int ans=0; rep(i,m){ int x=find(a[i].st); while(tag[x]&&x<=n)x++; if(x==n+1)continue; if(a[i].nd>=t[x]){ ans++; tag[x]=1; } } cout<<ans; }