NOIP2020.9.19模拟spongebob
Description
Input
输入文件包含 n + 1 行。
第一行一个整数 n,表示咸鱼 A 在这个月参加安保任务的次数。
接下来 n 行,每行两个整数 ai ,bi ,分别为这一次安保任务的两个参数。
Output
输出一行一个实数 y,表示在所有情况下薪水的最低值。
随后系统会将你的输出与答案进行比较,只有当你的输出与答案绝对误差不超过 10^−3 时才能得到
Sample Input
2
1 1
2 -1
Sample Output
1.50
Data Constraint
Hint
题解
题意
求min(sigma(|ai*x + bi|))
分析
显然是零点分段,零点的坐标为-a/b,选取的x一定为某个零点,那么每计算一次x的时间是O(n)的。考虑把绝对值拆掉,发现一个ax+b的函数跨过零点就要变号,且a’x+b’为单调函数,可以知道整个函数的解析式。
code
#include<cstdio>
#include<algorithm>
#define abs(x) (x>0?x:-(x))
#define min(x,y) (x<y?x:y)
#define N 300005
int a[N],b[N],p[N],n,suma;
double c[N],sum,ans=1e10;
using namespace std;
bool cmp(int x,int y) {return c[x]<c[y];}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d%d",&a[i],&b[i]),c[p[i]=i]=-1.0*b[i]/a[i];
sort(p+1,p+n+1,cmp);
for (int i=1;i<=n;++i) sum+=abs(a[i]*c[p[1]]+b[i]),suma-=abs(a[i]);
ans=sum;
for (int i=2;i<=n;++i){
suma+=abs(2*a[p[i-1]]);
sum+=suma*(c[p[i]]-c[p[i-1]]);
ans=min(ans,sum);
}
printf("%.6f",ans);
}