【AtCoder Grand Contest 040】B.Two Contests

题意

n n n段区间,要把他们分到两个不同的集合 S , T S,T S,T中,不能有剩余,每个区间只能在一个集合里,令 S S S中所有区间的交的长度为 l s ls ls T T T中所有区间的交为 l t lt lt,求 m a x { l s + l t } max\{ls+lt\} max{ls+lt}

题解

找到 L L L 最大的区间 p p p r r r 最小的区间 q q q,那么只有两种情况:
1. 1. 1. p , q p,q p,q在同一个集合内,那么即使把剩下的所有的区间都放到这个集合,最大值也不变,我们一定是把最长的放到另一个区间内,此时答案为 m a x l e n + m i n R − m a x L + 1 maxlen+minR-maxL+1 maxlen+minRmaxL+1
2. 2. 2. p , q p,q p,q不在同一个集合里,那么对于 p p p所在的集合,交的长度为 m i n { m a x { R i − m a x x L + 1 , 0 } } min\{max\{R_i-maxxL+1,0\}\} min{max{RimaxxL+1,0}},对于 q q q所在的集合,交的长度为 m i n { m a x { m i n R − L i + 1 , 0 } } min\{max\{minR-L_i+1,0\}\} min{max{minRLi+1,0}},这个问题可以转化为:一个数组,每个元素包含 a i , b i a_i,b_i ai,bil两个参数,把这个数组分成两部分,使得 m i n { a i } i ∈ s + m i n { b j } j ∈ t min\{a_i\}_{i\in{s}}+min\{b_j\}_{j\in{t}} min{ai}is+min{bj}jt最大,
考虑把a_i从大到小排序,同时维护 b i b_i bi后缀最小值,每次枚举 i i i即可。时间复杂度 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

代码:

#include<bits/stdc++.h>

using namespace std;
const int N = 2e5+100;
struct node{
    long long a,b;
}s[N];
bool cmp(node a,node b){
    return a.a>b.a;
}
long long L[N],R[N];
long long minnore[N];//后缀最小的B
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>L[i]>>R[i];
    long long maxx=0;long long minn=1e18;
    int p,q;
    long long maxxlength=0;
    for(int i=1;i<=n;i++){
        if(L[i]>maxx){
            maxx=L[i];
            p=i;
        }
        if(R[i]<minn){
            q=i;
            minn=R[i];
        }
        maxxlength=max(maxxlength,R[i]-L[i]+1);
    }
    long long ans1=maxxlength+(minn>=maxx?minn-maxx+1:0);
    for(int i=1;i<=n;i++){
        s[i].a=max(R[i]-maxx+1,0LL);
        s[i].b=max(minn-L[i]+1,0LL);
    }
  //  for(int i=1;i<=n;i++) cout<<i<<' '<<s[i].a<<' '<<s[i].b<<endl;
    sort(s+1,s+n+1,cmp);
    minnore[n+1]=(1e18);
    for(int i=n;i>=1;i--) minnore[i]=min(minnore[i+1],s[i].b);
    long long ans2=0;
    for(int i=1;i<=n-1;i++){
        ans2=max(ans2,s[i].a+minnore[i+1]);
    }
    cout<<max(ans1,ans2)<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值