【冗长的题目描述】
目标是使得f(y)尽可能的小,并求出y的取值范围。
【算法1】
根据数学证明,f(y)应该是成u形或者平底锅形,所以二分或者三分求“谷底”就可以了。
复杂度为O(n* log2n)
【算法2】
rt,我们考虑多段的线性函数。对于每一个绝对值函数。y<li时,等于-y+li;li<=y<=ri时,(最小)等于0;y>ri时,等于yi-ri;
将这n个函数合并,我们就可以得到一个新的一次函数,求得最小值。
顺序上我们可以按每个点的位置从小到大排序,经过某个点时,改变所在绝对值函数的表达式。
sort+n=O(n* log2n)
Code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=1e5+1000;
int minn,n,L,R;
int zt[maxn],l[maxn],r[maxn];
int k,b,now,t;
struct node{
int pos,id;
}lsh[maxn<<1];int cnt;
bool cmp(node x,node y){
return x.pos<y.pos;
}
signed main(){
freopen("linear.in","r",stdin);
freopen("linear.out","w",stdout);
cin>>n;k=-n;
for(int i=1;i<=n;i++){
scanf("%d%d",&l[i],&r[i]);
lsh[++cnt]=(node){l[i],i},lsh[++cnt]=(node){r[i],i};
b+=l[i];zt[i]=1;
}
sort(lsh+1,lsh+cnt+1,cmp);lsh[cnt+1].pos=1<<30;
now=lsh[1].pos,t=1;
minn=k*now+b,L=now,R=now;
while(t<=cnt){
do{
zt[lsh[t].id]++;
if(zt[lsh[t].id]==2) k++,b-=l[lsh[t].id];
else k++,b-=r[lsh[t].id];
t++;
}while(lsh[t].pos==now);
now=lsh[t].pos;
if(k<0){
if(minn>k*now+b)
minn=k*now+b,L=now,R=now;
}
else if(k==0){
if(k*now+b==minn) R=now;
}
}
printf("%d %d\n",L,R);
return 0;
}