Swapping problem解题报告

发布于 2021-11-19  964 次阅读


题目链接:https://codeforces.com/contest/1513/problem/F

通过观察可发现,只有a[i]>b[i]b[j]>a[j]时,交换b[i]b[j]的值才能减小最后总的绝对值和。设Li=min(ai,bi)Ri=max(ai,bi),将LiRi抽象为一条线段的左右端点,然后将满足开头条件的线段做一次比对,两线段重合部分长度的二倍即为最后答案减小的数字。现在问题转化为求解两类线段的最大重合长度,涉及到了线段区间问题很容易联想到的就是线段树了,后来我写了下发现完全不用,因为这并不涉及到动态更改的问题,离散化一下就ok了,剩下寻找最大重合度问题看代码吧,懒得写了

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX=2e5+5;
ll a[MAX],b[MAX],max1[MAX],max2[MAX];

int main(){
	ll n,ans=0;
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) cin>>b[i];
	vector<pair<ll,ll>>v1,v2;
	for(int i=1;i<=n;i++){
		if(a[i]<b[i]){
			v1.push_back(make_pair(a[i],b[i]));
		}
		else{
			v2.push_back(make_pair(b[i],a[i]));
		}
		ans+=abs(a[i]-b[i]);
	}
	sort(v1.begin(),v1.end());
	sort(v2.begin(),v2.end());
	for(int i=0;i<v1.size();i++){
		max1[i+1]=max(max1[i],v1[i].second);
	}
	for(int i=0;i<v2.size();i++){
		max2[i+1]=max(max2[i],v2[i].second);
	}
	ll maxn=0;
	for(auto seg:v1){
		ll fir=seg.first,sec=seg.second;
		auto it=upper_bound(v2.begin(),v2.end(),seg)-v2.begin();
		if(it==0) continue;
		maxn=max(maxn,min(sec,max2[it])-fir);
	}
	for(auto seg:v2){
		ll fir=seg.first,sec=seg.second;
		auto it=upper_bound(v1.begin(),v1.end(),seg)-v1.begin();
		if(it==0) continue;
		maxn=max(maxn,min(sec,max1[it])-fir);
	}
	cout<<ans-2*maxn;
	return 0;
}

回忆这理想不够理想,沿途逛世间一趟只有向上