P5139 z小f的函数 题解
EnofTaiPeople · · 题解
AK 竞赛后发题解,RP++!
这是一道很好的小学数学题,能教会我们二次函数移动问题。
我花了半小时,A 了这道题,给大家讲讲做法。
对五个指令,我们进行分开处理:
指令 1、2:考察的是二次函数的移动法则:
左加右减,上加下减。
意思是,对一个二次函数(顶点式)
向左(右)移
向上(下)移
于是上移代码如下:
scanf("%lf",&k1);c+=k1;
右移有些复杂,步骤如下:
-
将函数转为顶点式
-
在顶点式进行右移操作
-
顶点式转为一般式
代码如下:
inline void rigt(ld a,ld &b,ld &c,ld w){
ld d=b/(2*a)-w,e=(4*a*c-b*b)/(4*a);
c=e+d*d*a;b=d*2*a;return;
}
指令 3(有些麻烦,毕竟有 30% 数据没有指令 3)
这考察二次函数对称轴的转换和找特殊点。
对一个二次函数
一定有且仅有一个对称轴:
当函数图像关于点
-
开口方向会变;
-
对称轴会对直线
x=x_1 进行对称变换; -
函数中所有点都会关于点
P(x_1,y_1) 进行对称变换。
所以,指令 3 步骤如下:
-
计算原对称轴;
-
计算新对称轴;
-
-
用新对称轴倒推得到
y ; -
因为当
x=0 时,f(x)=c ,所以原函数过点Q(0,c) 将Q 点关于P 点进行对称变换,得到
由结论 3 可知,
代码如下:
inline void CHS(ld &a,ld &b,ld &c,ld x1,ld y1){
ld zhou=-b/(2*a);a=-a;
b=-(2*a)*(x1*2-zhou);
ld x2=2*x1,y2=y1*2-c;
c=y2-a*x2*x2-b*x2;return;
}
指令 4:求函数区间最值。
前置知识:对于二次函数
他在闭区间
所以,先判断顶点是否在闭区间
代码如下:
inline ld Min(ld a,ld b,ld c,ld k1,ld k2){
if(k1>k2)swap(k1,k2);
ld dl=k1*k1*a+k1*b+c,dr=k2*k2*a+k2*b+c;
ld dm=-b/(2*a),tans=min(dl,dr);
if(dm>=k1&&dm<=k2)
tans=min(tans,dm*dm*a+dm*b+c);
return tans;
}
inline ld Max(ld a,ld b,ld c,ld k1,ld k2){
if(k1>k2)swap(k1,k2);
ld dl=k1*k1*a+k1*b+c,dr=k2*k2*a+k2*b+c;
ld dm=-b/(2*a),tans=max(dl,dr);
if(dm>=k1&&dm<=k2)
tans=max(tans,dm*dm*a+dm*b+c);
return tans;
}
指令 5:这是除指令 1 之外最简单的了。
题意即
用左式减去右式,得到
注意到
即判别式
代码如下:
inline int EJ(ld a,ld b,ld c,ld u,ld v,ld w){
a-=u;b-=v;c-=w;
if(b*b>=4*a*c)return 2;
else return 0;
}
综上,无注释 AC 代码:
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef double ld;
inline void rigt(ld a,ld &b,ld &c,ld w){
ld d=b/(2*a)-w,e=(4*a*c-b*b)/(4*a);
c=e+d*d*a;b=d*2*a;return;
}
inline void CHS(ld &a,ld &b,ld &c,ld x1,ld y1){
ld zhou=-b/(2*a);
b=-(2*(a=-a))*(x1*2-zhou);
ld x2=2*x1,y2=y1*2-c;
c=y2-a*x2*x2-b*x2;return;
}
inline ld Min(ld a,ld b,ld c,ld k1,ld k2){
if(k1>k2)swap(k1,k2);
ld dl=k1*k1*a+k1*b+c,dr=k2*k2*a+k2*b+c;
ld dm=-b/(2*a),tans=min(dl,dr);
if(dm>=k1&&dm<=k2)
tans=min(tans,dm*dm*a+dm*b+c);
return tans;
}
inline ld Max(ld a,ld b,ld c,ld k1,ld k2){
if(k1>k2)swap(k1,k2);
ld dl=k1*k1*a+k1*b+c,dr=k2*k2*a+k2*b+c;
ld dm=-b/(2*a),tans=max(dl,dr);
if(dm>=k1&&dm<=k2)
tans=max(tans,dm*dm*a+dm*b+c);
return tans;
}
inline int EJ(ld a,ld b,ld c,ld u,ld v,ld w){
a-=u;b-=v;c-=w;
if(b*b>=4*a*c)return 2;
else return 0;
}
inline void gofans(){
ld a,b,c,k1,k2,u,v,w;
int n,p;scanf("%lf%lf%lf%d",&a,&b,&c,&n);
while(n--){
scanf("%d",&p);
switch(p){
case 1:scanf("%lf",&k1);c+=k1;break;
case 2:scanf("%lf",&k1);rigt(a,b,c,k1);break;
case 3:scanf("%lf%lf",&k1,&k2);
CHS(a,b,c,k1,k2);break;
case 4:scanf("%lf%lf",&k1,&k2);
printf("%.2lf %.2lf\n",Min(a,b,c,k1,k2),Max(a,b,c,k1,k2));
break;case 5:scanf("%lf%lf%lf",&u,&v,&w);
printf("%d\n",EJ(a,b,c,u,v,w));break;
default:while(true)printf("NO-ANSWER!\n");break;
}
}
k1=-b/(2*a);
printf("%.2lf\n",k1*k1*a+k1*b+c);
return;
}
int main(){
int T;scanf("%d",&T);
while(T--)gofans();
return 0;
}
完结撒花!