求两个集合中区间交集最大值

本文介绍了如何通过C++编程解决一个区间优化问题,通过交换正区间和逆区间来最小化绝对差值之和,利用排序和前缀最大值计算交集最大值。

题目

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e6 + 5;
int n1, n2;
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    int n, i, j;
    cin >> n;
    int sum = 0;
    vector<pair<int, int>> s, t;//动态分配内存,直接开1e6会MLE
    s.push_back({-1e9, -1e9}), t.push_back({-1e9, -1e9});
    vector<int> a(n + 1), b(n + 1);
    for(i = 1; i <= n; i++){
        cin >> a[i];
    }
    //画图后可以发现,设p[i] = {min(a[i], b[i]), max(a[i], b[i])}, p[i]看成一个区间,
    //设a[i] < b[i]的为正区间,a[i] > b[i]的为逆区间,只有交换一个正区间和逆区间的a,
    //|a - b|之和才会减小,减小的值为2 * 区间交集的长度
    //把正区间放到s,逆区间放到t,问题转化为求s中区间和t中区间交集的最大值
    for(i = 1; i <= n; i++){
        cin >> b[i];
        if(a[i] < b[i]) s.push_back({a[i], b[i]});
        else if(a[i] > b[i]) t.push_back({b[i], a[i]});
        sum += abs(a[i] - b[i]);
    }
    n1 = s.size() - 1, n2 = t.size() - 1;
    sort(s.begin() + 1, s.end());//排序
    sort(t.begin() + 1, t.end());
    vector<int> pre_maxs(n1 + 5, -1e9), pre_maxt(n2 + 5, -1e9);
    for(i = 1; i <= n1; i++){
        pre_maxs[i] = max(pre_maxs[i - 1], s[i].second);//求前缀右端点的最大值
    }
    for(i = 1; i <= n2; i++){
        pre_maxt[i] = max(pre_maxt[i - 1], t[i].second);
    }
    int maxx = 0;
    for(i = 1; i <= n1; i++){
        int pos = upper_bound(t.begin() + 1, t.end(), s[i]) - t.begin() - 1;
        //对于s中的一个区间,在t中找到第一个左端点大于s[i]左端点的区间,那么t中该区间左边都是 
        左端点小于等于s[i]左端点的,取前缀右端点最大的一个区间
        if(pos >= 1) maxx = max(maxx, min(s[i].second, pre_maxt[pos]) - s[i].first);
    }
    for(i = 1; i <= n2; i++){//因为上面for循环只考虑t[i].first <= s[i].firs的情况,所以对t 
                             也重复一遍
        int pos = upper_bound(s.begin() + 1, s.end(), t[i]) - s.begin() - 1;
        if(pos >= 1) maxx = max(maxx, min(t[i].second, pre_maxs[pos]) - t[i].first);
    }
    cout << sum - 2 * maxx;
    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__night_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值