statement
有数组A与数组B,你可以选择A的某个数与B的某个数搭配,每次搭配需要满足数组中每个数不重复选且(a_i+b_ileq s),令(d_i=abs(a_i-b_i)),(D=max(d_1,d_2,..,d_n)),求完成n组匹配能得到的最小的D。
input
(nleq 2 imes 10^5)
(a_i,b_i,sleq 10^9)
idea
啊,这题竟然比赛时没做出来quq...实在没想到怎么贪。
首先看到D是一堆数的最大,又要求D的最小,最大的最小与最小的最大很明显是二分答案的信号。我们二分每个D,对于数组A每个数x对应的B数组的数y需要满足
egin{cases} &yleq s-x\ &yleq D+x\ &ygeq x-d end{cases}
我们将A,B数组排序,按照以上不等式,每个A数组对应可选的B数组为一段序列,我们将以上序列排序后从左到右枚举B数组每个数。首先,如果当前的数在一段序列内,一定要拿,因为每次匹配都是相同的贡献,你留着不拿,给后面的数拿并不会增加贡献。其次,如果有多个序列段能进行匹配,一定要拿r(序列右端点)最小的,因为后面的数l一定比当前数大,所以l不能产生约束,但是当前拿r最小的,可能可以给后面更多的数得到匹配。所以就这么贪心地拿,在$O(nlog n)$内可以完成匹配。而二分答案次数为$O(log s)$,故总时间复杂度为$O(nlog nlog s)$。代码
/*************************************************************************
> File Name: 3.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https://blog.csdn.net/Pig_cfbsl
> Created Time: 2020/10/5 14:20:58
************************************************************************/
#include<bits/stdc++.h>
#define For(i,a,b) for(register int i=(a);i<=(b);++i)
#define pb push_back
#define pr pair<int,int>
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define LL long long
using namespace std;
int read(){
char x=getchar(); int u=0,fg=0;
while(!isdigit(x)){ if(x=='-') fg=1; x=getchar(); }
while(isdigit(x)){ u=(u<<3)+(u<<1)+(x^48); x=getchar(); }
return fg?-u:u;
}
const int maxx=2e5+10;
int a[maxx],b[maxx],n,p,q,s;
struct cmp{
bool operator () (const pr &a,const pr &b)const{
return a.se>b.se;
}
};
queue<pr>Q;
priority_queue<pr,vector<pr>,cmp>que;
bool check(int d){
int tmp=0;
while(!Q.empty()) Q.pop();
while(!que.empty()) que.pop();
For(i,1,p){
int x=lower_bound(b+1,b+q+1,a[i]-d)-b,lim=min(a[i]+d,s-a[i]);
int y=upper_bound(b+1,b+q+1,lim)-b-1;
if(x<=y) Q.push(mk(x,y));
}
For(i,1,q){
while(!Q.empty() && Q.front().fi<=i){
que.push(Q.front());
Q.pop();
}
while(!que.empty()){
int r=que.top().se;
que.pop();
if(r<i) continue;
++tmp;
break;
}
if(tmp>=n) return tmp>=n;
}
return tmp>=n;
}
int main()
{
// freopen("input.in","r",stdin);
// freopen("output.out","w",stdout);
n=read(); p=read(); q=read(); s=read();
For(i,1,p) a[i]=read();
For(i,1,q) b[i]=read();
sort(a+1,a+p+1);
sort(b+1,b+q+1);
int l=0,r=1e9,mid,ans=-1;
while(l<=r){
mid=(l+r)>>1;
if(check(mid)){ r=mid-1; ans=mid; }
else l=mid+1;
}
printf("%d
",ans);
return 0;
}