【冗长的题目描述】
国庆七连测(二)多段线性函数
目标是使得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;
}

相关文章:

  • 2021-12-23
  • 2022-12-23
  • 2021-12-03
  • 2022-02-07
  • 2021-07-21
  • 2022-01-01
  • 2021-12-06
猜你喜欢
  • 2021-12-05
  • 2022-01-02
  • 2022-01-02
  • 2021-08-17
  • 2021-11-28
  • 2022-02-08
  • 2022-02-07
相关资源
相似解决方案