好题。首先不难想到二分答案。验证就是写出状态
n2
的
DP
,类似 二取一维数组 的搞法:
fi,j
表示前
i
个点已走过,两个人分别在
fi,j→fi+1,j(ai+1−aj≤mid),fi,j→fi+1,i(ai+1−ai≤mid)
怎么优化呢? 可以发现这个
DP
很特殊,他是布尔形的,且转移方程很有特点,当
i
推一层时,从
所以我们就可以用
set
维护
DP
。即开个
set
维护哪些
j
是
复杂度
O(nlogn)
#include<cstdio>
#include<cmath>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=200005;
set<int> S;
int n,a[maxn],ans;
bool check(int lim){
if(abs(a[1]-a[2])>lim) return false;
S.clear(); S.insert(a[1]);
for(int i=3;i<=n+2;i++){
S.insert(a[i-1]);
while(!S.empty()&&abs(a[i]-(*S.begin()))>lim) S.erase(*S.begin());
while(!S.empty()&&abs(a[i]-(*S.rbegin()))>lim) S.erase(*S.rbegin());
if(S.empty()) return false;
}
return true;
}
int main(){
freopen("cf875E.in","r",stdin);
freopen("cf875E.out","w",stdout);
scanf("%d%d%d",&n,&a[1],&a[2]);
for(int i=3;i<=n+2;i++) scanf("%d",&a[i]);
int L=0,R=1e9;
while(L<=R){
int mid=(L+R)>>1;
if(check(mid)) R=mid-1, ans=mid;
else L=mid+1;
}
check(1);
printf("%d\n",ans);
}