洛谷 P1883 【模板】三分 | 函数

原题

题目描述

给定 n 个二次函数 f1​(x),f2​(x),…,fn​(x)(均形如 ax2+bx+c),设 𝐹(𝑥)=F(x)=max{f1​(x),f2​(x),...,fn​(x)},求 𝐹(𝑥)F(x) 在区间[0,1000] 上的最小值。

输入格式

输入第一行为正整数 T,表示有 T 组数据。

每组数据第一行一个正整数 n,接着 n 行,每行 3 个整数a,b,c,用来表示每个二次函数的 3 个系数,注意二次函数有可能退化成一次。

输出格式

每组数据输出一行,表示 F(x) 的在区间[0,1000] 上的最小值。答案精确到小数点后四位,四舍五入。

输入输出样例

输入 #1

2
1
2 0 0
2
2 0 0
2 -4 2

输出 #1

0.0000
0.5000

说明/提示

解题思路

这是一个二分方法。

其实想到了这题就很简单,F(x)就是由[0,1000]区间内f1,f2等函数的最大值构成的,那么F(x)也一定是一个凹的,这样我们在[l,r]只要找到mid(f2),然后找到mid-eps(f1),mid+eps(f3),如果f1>f2,f3>f2,那么答案就出来了,f1<f2<f3代表是单调递增,缩小范围[l,mid-eps],反之就往[mid+eps,r]找,直到满足条件。

AC代码

#include <iostream>
#define eps 0.00000001//大于这个就精度出问题
using namespace std;
#include <algorithm>
int n,T;
double a[10009],b[10009],c[10009],f1,f2,f3;//a,b,c必须是double,不然强转会浪费很多时间 
double function(double x){
	double res=-1000000000;
	for(int i=1;i<=n;i++) res=max(res,a[i]*x*x+b[i]*x+c[i]);
	return res;
}
int main(){
	cin>>T;
	while(T--){
		cin>>n;
		for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&a[i],&b[i],&c[i]);
		double l=0,r=1000;
		double mid=(l+r)/2,f1,f2,f3;
		f1=function(mid-eps);
		f2=function(mid);
		f3=function(mid+eps);
		while(!((r-l<eps)||((f1>f2)&&(f3>f2)))){//r-l>eps||!((f1>f2)&&(f3>f2))
			if((f1>f2)&&(f2>f3)) l=mid+eps;
			if((f1<f2)&&(f2<f3)) r=mid-eps;
			mid=(l+r)/2;
			f1=function(mid-eps);
			f2=function(mid);
			f3=function(mid+eps);
		}
		printf("%.4lf\n",f2);
	}
	return 0;
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

j2189259313

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值