School Reunion(接触k个区间的最短区间)

原题: 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;
}


猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/82956762