【GMOJ6800】模拟spongebob

题目

题目链接:https://gmoj.net/senior/#main/show/6800
给出 \(n\) 和两个长度为 \(n\) 的数组 \(a,b\),求

\[\min\{\sum^{n}_{i=1}|a_ix+b_i|\} \]

其中 \(x\in \mathbb{R}\)

思路

先把 \(a=0\) 的所有直线的 \(|b|\) 加到答案里。
对于剩余的直线,我们按照他们与 \(x\) 轴交点排序,依次枚举交点区间并计算出此时最优的 \(x\),判断 \(x\) 与当前区间位置分别计算答案即可。
时间复杂度 \(O(n\log n)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=300010;
int n,m;
ll sum,suma,sumb;
double ans;

struct node
{
	ll a,b;
	double p;
}a[N];

bool cmp(node x,node y)
{
	if (x.a==0) return 0;
	if (y.a==0) return 1;
	return x.p<y.p;
}

int main()
{
	freopen("spongebob.in","r",stdin);
	freopen("spongebob.out","w",stdout);
	scanf("%d",&m); n=m;
	for (int i=1;i<=m;i++)
	{
		scanf("%lld%lld",&a[i].a,&a[i].b);
		if (a[i].a!=0) a[i].p=-1.0*a[i].b/a[i].a;
			else sum+=abs(a[i].b),n--;
	}
	sort(a+1,a+1+m,cmp);
	for (int i=1;i<=n;i++)
		if (a[i].a>0) suma-=a[i].a,sumb-=a[i].b;
			else suma+=a[i].a,sumb+=a[i].b;
	a[0].p=-10000000000000000.0; a[n+1].p=10000000000000000.0;
	ans=10000000000000000.0;
	for (int i=1;i<=n+1;i++)
	{
		double l=a[i-1].p,r=a[i].p,x=-1.0*sumb/suma;
		if (l<=x && x<=r) ans=0;
		if (x<l) ans=min(ans,suma*l+sumb);
		if (x>r) ans=min(ans,suma*r+sumb);
		if (a[i].a>0) suma+=2LL*a[i].a,sumb+=2LL*a[i].b;
			else suma-=2LL*a[i].a,sumb-=2LL*a[i].b;
	}
	printf("%.8lf",ans+sum);
	return 0;
}
posted @ 2020-10-16 17:27  stoorz  阅读(88)  评论(0编辑  收藏  举报