原题: https://cn.vjudge.net/problem/Gym-101864L
题意:
给n个最大1e9的区间,你需要找一个区间使之与其中至少k个区间有接触,求这个区间的最短长度
解析:
第一种做法就是枚举每个区间的终点,求出往后延多少长度才能接触k个区间。需要先计算出和这个终点en已经接触的区间个数:终点大于等于en的区间-起点大于en的区间。然后求出第一个起点大于en的区间,往后找需要的个数即可。最后做起点往左延只需要翻转所有区间再做一遍上面的操作即可
(后来发现从终点往后找起点,已经包含了从起点往前找终点的情况,所以第二部分可以省略)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pill pair<int,int>
const int N=1e5+9;
pill ed[N];
int st[N],en[N];
int main()
{
int t;cin>>t;int ca=0;
while(t--){
int p,n;scanf("%d%d",&n,&p);
for(int i=1;i<=n;i++){
scanf("%d%d",&ed[i].first,&ed[i].second);
st[i]=ed[i].first;
en[i]=ed[i].second;
}
if(p==1){
printf("Case %d: 0\n",++ca);
continue;
}
sort(st+1,st+1+n);
sort(en+1,en+1+n);
int ans=2e9;
for(int i=1;i<=n;i++){
int pos=upper_bound(st+1,st+1+n,ed[i].second)-st;//第一个大于en的
int have=((n-(lower_bound(en+1,en+1+n,ed[i].second)-en)+1)-
(n-(upper_bound(st+1,st+1+n,ed[i].second)-st)+1));//已经有的
int need=p-have;//还需要的
if(need<=0){ans=0;break;}
int idx=pos+need-1;
if(idx>n)continue;
ans=min(ans,st[idx]-ed[i].second);
}
for(int i=1;i<=n;i++){
int tmp=2000000000-ed[i].first;
ed[i].first=2000000000-ed[i].second;
ed[i].second=tmp;
st[i]=ed[i].first;
en[i]=ed[i].second;
}
sort(st+1,st+1+n);
sort(en+1,en+1+n);
for(int i=1;i<=n;i++){
int pos=upper_bound(st+1,st+1+n,ed[i].second)-st;
int have=((n-(lower_bound(en+1,en+1+n,ed[i].second)-en)+1)-(n-(upper_bound(st+1,st+1+n,ed[i].second)-st)+1));
int need=p-have;
if(need<=0){ans=0;break;}
int idx=pos+need-1;
if(idx>n)continue;
ans=min(ans,st[idx]-ed[i].second);
}
printf("Case %d: %d\n",++ca,ans);
}
return 0;
}
第二种做法比较难想到,我们不用考虑这些区间是什么,直接对起点sort,终点sort。然后从第p个起点开始枚举。首先,前面一定有至少p-1个起点,那么我对于枚举到的第i个起点找第i-(p-1)个终点,也就是说,这样做就可以保证包含了p个区间
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
typedef long long ll;
ll st[maxn],en[maxn];
ll p,n;
int main(){
int t,ca=0;
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&n,&p);
for(int i=1;i<=n;i++)scanf("%lld %lld",&st[i],&en[i]);
sort(st+1,st+1+n);
sort(en+1,en+1+n);
ll ans=2e18;
for(int i=p;i<=n;i++){
ll A=st[i]-en[i-(p-1)];
ans=min(ans,A);
}
if(ans<0)ans=0;
printf("Case %d: %lld\n",++ca,ans);
}
return 0;
}