P1883 函数

先放一个样例的函数图像,这样直观…
这个是样例1:
这个是样例1
最低点是0,这个很明显的,经过原点

这个是样例2:
在这里插入图片描述
交叉处的高度为0.5

虽然看过了样例,但貌似还是一脸懵逼…

  • 给定n个二次函数f1(x),f2(x),…,fn(x)(均形如ax^2+bx+c),设F(x)=max{f1(x),f2(x),…,fn(x)},求F(x)在区间[0,1000]上的最小值
    总结一下不就是最大值的最小值吗?好了,这题二分(裸裸的都是套路)
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cmath>
#include<string.h>
#include<algorithm>
using namespace std;
double read(void)//快读,不多说了
{
  long long x=0,w=1,m=1,p=0;
  char c=getchar();
  for(;c<'0'||c>'9';c=1,c=getchar())
  if(c=='-')w*=-1;
  for(;c>='0'&&c<='9'||c=='.';c=1,c=getchar())
  if(c>='0'&&c<='9')
  {x=(x<<1)+(x<<3)+(c^48);m*=p?10:1;}
  else p=1;
  return (x*w*1.0-0.0+m)/(m*1.0+0.0)-1;
}
double Top(double a,double b,double c)//计算函数顶点的y坐标
{
  //因为f(x)=ax^2+bx+c
  //所以f'(x)=2*a*x+b
  //因为顶点的切线的斜率为0
  //所以2*a*x+b=0
  //x=-b/2/a
  //带入原式便得出一下的公式
  double delta=b*b-4*a*c;
  return -delta/4/a;
}
double f(double a,double b,double c,double x)//求出该函数在x时的值
{
  return a*x*x+b*x+c;
}
double SPJ=0.00000001;//spj要设的小一点,不然会被卡精度
double A[10002],B[10002],C[10002],K[10002],BB[10002];//A,B,C分别记录二次函数的a,b,c;K,BB分别记录一次函数的k,b
double get_l(double a,double b,double c,double y)//给定一个二次函数(a!=0),与常数函数y上靠左的焦点
{
  c=c-y;
  double delta=b*b-4*a*c;
  return (-b-sqrt(delta))/2/a;
}
double get_r(double a,double b,double c,double y)//靠右的焦点
{
  c=c-y;
  double delta=b*b-4*a*c;
  return (-b+sqrt(delta))/2/a;
}
double get_one(double k,double b,double y)//求一个一次函数,与常数函数y上的焦点
{
  return (y-b)/k;
}
bool check(double mid,int one,int two)//判断mid是否成立
{
  int i;
  double l=0,r=1000,L,R;
  for(i=1;i<=two;i++)//先判断二次函数
  {
  	L=get_l(A[i],B[i],C[i],mid);
  	R=get_r(A[i],B[i],C[i],mid);
    if(R<l||L>r)return 0;//二次函数符合条件的区间没有和先前符合条件的区间有交集
    //缩小区间
  	l=max(l,L);
  	r=min(r,R);
    l=max(l,0.0);
    l=min(l,1000.0);
    r=max(r,0.0);
    r=min(r,1000.0);
  }
  for(i=1;i<=one;i++)//再判断一次函数
  {
  	L=f(0,K[i],BB[i],l);//找到区间左右改函数的值
	R=f(0,K[i],BB[i],r);
  	if(L>mid&&R>mid)return 0;//如果都大于就不成立
  	//缩小区间
  	if(L<mid&&R>mid)r=get_one(K[i],BB[i],mid);
  	if(L>mid&&R<mid)l=get_one(K[i],BB[i],mid);
  }
  return 1;//符合条件
}
void QAQ()
{
  int n=read(),i,j,k,one=0,two=0;
  double Min=-1e12,Max=1e12,l,r,a,b,c;
  for(i=1;i<=n;i++)
  {
  	a=read();
  	b=read();
  	c=read();
  	if(a!=0)//二次函数和一次函数分开放
  	{
  	  two++;
  	  A[two]=a;
  	  B[two]=b;
  	  C[two]=c;
  	  Min=max(Min,Top(a,b,c));
  	  Max=max(Max,max(f(a,b,c,0),f(a,b,c,1000)));//找二分区间
    }
    else
    {
      one++;
      K[one]=b;
      BB[one]=c;
	}
  }
  r=Max;
  l=Min;
  double mid,ans;
  while(r-l>SPJ)//二分
  {
  	mid=(l+r)/2;
  	if(check(mid,one,two)){r=mid-SPJ;/*结果可能更小,所以r减小*/ans=mid;/*记录下ans*/}else l=mid+SPJ;
  }
  printf("%.4lf\n",ans);//输出ans,保留4位小数
}
int i,t;
int main()
{
  t=read();
  for(i=1;i<=t;i++)//执行t遍操作
  {
    QAQ();
  }
  return 0;
}

二分太明显了…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用中提到了Hive中的pmod函数,它有两种重载形式:pmod(int a, int b)和pmod(double a, double b。该函数的作用是返回a除以b的余数。例如,pmod(9, 4)返回1,pmod(-9, 4)返回-1。 Hive还提供了许多其他函数,包括数学函数、类型转换函数、条件函数、字符函数、聚合函数和表生成函数等。您可以通过在Hive中执行一些命令来查看这些函数的信息。 对于日期函数,Hive在版本2.2.0及以上提供了dayofweek函数,用于获取一个日期是星期几。在低版本的Hive中,原生并未提供dayofweek函数。但可以使用一种技巧来获取星期几,即使用pmod函数结合datediff函数。例如,pmod(datediff('${date}', '1920-01-01') - 3, 7)可以返回给定日期是星期几。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [29. 大数据---hive的常用函数(一(最全的函数操作))](https://blog.csdn.net/u014579001/article/details/126026596)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Hive学习(7)pmod()函数详解](https://blog.csdn.net/Dreamy_zsy/article/details/113371000)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值