题目描述
三分大水?
我们容易证明,fmin是一个非严格单峰函数。
对于一个xi,随着y的增大,它的贡献先是一个减量,再是一个为0的常量,最后是一个增量。随着y的增大,fmin的增量应该是增量和减减量和。因为每一个都是由增量变成减量,因此fmin的增量越来越大,所以fmin单峰。因为平板的存在,fmin只能算是非严格单峰函数。
因此我们考虑三分出极值,再二分出取值范围。
三分在有平板的情况下好像是错的?例如在极点右端造一大段平板,那么如果两个三分点都卡在这段平板上,把左端调整会使得我们错过极点。
但是这题三分没有错,为什么?
如果出现了平板,此时fmin的增量就是0。这题fmin的增量是单调的,增量为0说明是一条切线,这个时候平板处一定是极值。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
int L[maxn],R[maxn];
ll ans;
int i,j,k,l,r,mid,mid1,mid2,t,n,m,mi,mx,ansl,ansr,id;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
ll f(int x){
int i;
ll t=0;
fo(i,1,n){
if (L[i]<=x&&x<=R[i]) continue;
else if (x<L[i]) t+=(ll)(L[i]-x);
else t+=(ll)(x-R[i]);
}
return t;
}
int main(){
freopen("linear.in","r",stdin);freopen("linear.out","w",stdout);
n=read();
mi=2000000000;
fo(i,1,n) L[i]=read(),R[i]=read(),mi=min(mi,L[i]),mx=max(mx,R[i]);
l=mi;r=mx;
while (l<r){
if (r-l==1){
if (f(l)>f(r)) l=r;
break;
}
else if (r-l==2){
mid=(l+r)/2;
if (f(l)>f(mid)) l=mid;
if (f(l)>f(r)) l=r;
break;
}
mid1=l+(r-l+1)/3;mid2=l+(r-l+1)/3*2;
if (f(mid1)<f(mid2)) r=mid2;else l=mid1;
}
id=l;
ans=f(id);
l=mi;r=id;
while (l<r){
mid=(l+r)/2;
if (f(mid)>ans) l=mid+1;else r=mid;
}
ansl=l;
l=id;r=mx;
while (l<r){
mid=(l+r+1)/2;
if (f(mid)>ans) r=mid-1;else l=mid;
}
ansr=l;
printf("%d %d\n",ansl,ansr);
}