牛客多校第一场H题

文章探讨了一种利用二分法和分类讨论来解决数组中元素交换以最小化某种指标的问题。通过对不同顺序状态的分析,如正序、反序和相交情况,以及使用多集数据结构维护元素,找到最优解。最后通过示例代码展示了算法的实现过程。
摘要由CSDN通过智能技术生成

题目链接
考察知识点 : 二分 , 抽象提取分类讨论 考察知识点: 二分 , 抽象提取分类讨论 考察知识点:二分,抽象提取分类讨论
先考察交换ax,ay或者交换bx,by的情况
我们可以发现对于我们选定要交换的两对数,交换ax,ay和bx,by减小的值是一样的,所以为了方便讨论,我们都以交换bx,by为例
ax ay
bx by

ax < bx && ay < by 我们叫做 正序
ax < bx && ay > by 我们叫做 反序
//正序相交 ax ay bx by 交换bx,by: ax ay by bx 无变化,不考虑
//正序包络 ax ay by bx 交换bx,by: ax ay bx by 无变化,不考虑
//正序不交 ax bx ay by 交换bx,by: ax by ay bx 变大,不考虑
//反序相交 ax by bx ay 交换bx,by: ax bx by ay 变小2*|bx-by| -> 反序相交变成反序不交 //维护lower_bound(l) 然后判断是否小于等于r res=min(res,2*|bx-by|)
//反序包络 ax by ay bx 交换bx,by: ax bx ay by 变小2*|by-ay| -> 反序包络变成正序不交 //维护反序lmin if l >= lmin res = max(res, len*2)
//反序不交 ax bx by ay 交换bx,by: ax by bx ay 变大,不考虑
这里因为需要区分正序反序,所以我们需要每对数的大小关系,所以我们用type表示这一对数的类型,即l<r,就是1反之为0,这样我们就清楚了每一对数的大小情况,然后我们必须在遍历1类型的数对时,用0类型中的数对来凑反序包络,或者反序相交来更新答案


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
LL n;
struct node{
    LL l, r;
    int type;
    node(LL _l,LL  _r)
    {
    	type = _l < _r;
        l = min(_l, _r);
        r = max(_l, _r); 
    }
    bool operator < (const node & tem) const
    {
        return r > tem.r;
    };
};

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    vector<LL> a(n+10), b(n+10);
    for(int i = 1; i <= n; i ++)
    {
        cin >> a[i];
    }
    for(int i = 1; i <= n; i ++)
    {
        cin >> b[i];
    }
   	vector<node> q;
   	LL sum = 0;
   	for(int i = 1; i <= n; i ++)
   	{
   		sum += abs(a[i] - b[i]);
   		q.emplace_back(a[i], b[i]);
   	}
    sort(q.begin(), q.end());
    LL overlap = 0;
    multiset<int> S, T;//T : type=1                  S : type = 0

    for(int i = 0; i <= n-1; i ++ )
    {
    	int type = q[i].type;
    	LL l = q[i].l;
    	LL r = q[i].r;
    	if(type == 0)
    	{	
    		if(T.size())
    		{
    			if(l >= (*T.begin()))
    			{
    				overlap = max(overlap, 2*(r-l));
    			}
    			auto it = T.lower_bound(l);
    			if(it != T.end() && (*it) <= r)
    			{
    				overlap = max(overlap, 2*(r-(*it)));
    			}
    		}
    
    		S.insert(l);
    	}
    	else if(type == 1)
    	{
    		if(S.size())
    		{
    			if(l >= (*S.begin()))
    			{
    				overlap = max(overlap, 2*(r-l));
    			}
    			auto it = S.lower_bound(l);
    			if(it != S.end() && (*it) <= r)
    			{
    				cout << "1 " << 2*(r-(*it)) << endl;
    				overlap = max(overlap, 2*(r-(*it)));
    			}
    		}
    		T.insert(l);	
    	}
    }

    cout << (sum-overlap) << endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

向夕阳Salute

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

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

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

打赏作者

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

抵扣说明:

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

余额充值