题解:P10435 [JOISC 2024 Day2] 有趣的家庭菜园 5
C1942huangjiaxu · · 题解
我们将
考虑如果已经确定了花盆颜色,怎么安排最优。
那么问题就是,给定
可以发现,将
证明考虑,假如我们已经知道了最优答案为
那么这相当于一个二分图匹配问题,注意到排序后每个
上述证明过程启示我们考虑二分答案,判断是否存在可行解。
注意到
枚举半圆似乎并不好解决,我们考虑枚举圆环上的点,判断经过每个点的
首先用双指针求出每个
然后题目还保证了一个关键性质,那就是
那么我们按照顺时针的顺序考虑经过一个
那么我们用差分的方式对一段区间的半圆做标记,可行的半圆就是被所有点都标记的半圆。
上述过程都可以在线性的复杂度内解决,加上二分的复杂度,时间复杂度
参考代码:
#include<bits/stdc++.h>
using namespace std;
const int N=6e5+5;
int n,m,a[N],b[N],c[N],lim,ans[N],Ans[N],vl[N],vr[N],p1[N],p2[N];
void upd(int o,int l,int r){
l=(l+o)%m,r=(r+o)%m;
if(l>r)++ans[0],--ans[r+1],++ans[l];
else ++ans[l],--ans[r+1];
}
void solve(int *v){
for(int i=0,j=1;i<n;++i){
while(j<=n&&v[j]<a[i]&&a[i]-v[j]>lim)++j;
vl[i]=j;
}
for(int i=n-1,j=n;~i;--i){
while(j&&v[j]>a[i]&&v[j]-a[i]>lim)--j;
vr[i]=j;
}
for(int i=m-1,j=1;i>=n;--i){
while(j<=n&&v[j]<a[i]&&a[i]-v[j]>lim)++j;
vl[i]=j;
}
for(int i=n,j=n;i<m;++i){
while(j&&v[j]>a[i]&&v[j]-a[i]>lim)--j;
vr[i]=j;
}
for(int i=0;i<m;++i)ans[i]=0;
for(int i=0;i<n;++i)if(vl[i]<=vr[i]){
int ct=i+1+m-max(p1[i],i+n+1);
if(ct<vl[i])continue;
if(p1[i]>=i+n+1){
int dt=p1[i]-(i+n+1);
if(ct-(n-dt)>vr[i])continue;
if(ct<=vr[i])upd(i+n+1,0,min(n-1,dt+ct-vl[i]));
else upd(i+n+1,dt+ct-vr[i],min(n-1,dt+ct-vl[i]));
}else{
int dt=i+n+1-p1[i];
if(ct-(n-dt)>vr[i])continue;
if(ct-(n-dt)>=vl[i])upd(i+n+1,max(0,ct-vr[i]),n-1);
else upd(i+n+1,max(0,ct-vr[i]),ct-vl[i]);
}
}
for(int i=n;i<m;++i)if(vl[i]<=vr[i]){
int ct=1+max(0,p2[i]-(i-n));
if(ct>vr[i])continue;
if(p2[i]>=i-n){
int dt=p2[i]-(i-n);
if(ct+(n-dt)<vl[i])continue;
if(ct>=vl[i])upd(i-n+1,0,min(n-1,dt+vr[i]-ct));
else upd(i-n+1,dt+vl[i]-ct,min(n-1,dt+vr[i]-ct));
}else{
int dt=i-n-p2[i];
if(ct+(n-dt)<vl[i])continue;
if(ct+(n-dt)<=vr[i])upd(i-n+1,max(0,vl[i]-ct),n-1);
else upd(i-n+1,max(0,vl[i]-ct),vr[i]-ct);
}
}
for(int i=1;i<m;++i)ans[i]+=ans[i-1];
}
bool check(int mid){
lim=mid;
solve(b);
for(int i=0;i<m;++i)Ans[i]=ans[i];
solve(c);
for(int i=0;i<m;++i)if(Ans[i]+ans[(i+n)%m]==m)return true;
return false;
}
int main(){
scanf("%d",&n);
m=2*n;
for(int i=0;i<m;++i)scanf("%d",&a[i]);
for(int i=1;i<=n;++i)scanf("%d",&b[i]);
for(int i=1;i<=n;++i)scanf("%d",&c[i]);
for(int i=0,j=m-1;i<n;++i){
while(a[j]<a[i])p2[j--]=i-1;
p1[i]=j+1;
if(i==n-1)while(j>=n)p2[j--]=i;
}
sort(b+1,b+n+1),sort(c+1,c+n+1);
int l=0,r=1e9;
while(l<r){
int mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
printf("%d\n",l);
return 0;
}