1 条题解

  • 0
    @ 2025-8-24 22:07:32

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar EnofTaiPeople
    MGXS

    搬运于2025-08-24 22:07:32,当前版本为作者最后更新于2021-08-08 15:33:01,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    AK 竞赛后发题解,RP++!

    这是一道很好的小学数学题,能教会我们二次函数移动问题。

    我花了半小时,A 了这道题,给大家讲讲做法。

    对五个指令,我们进行分开处理:

    指令 1、2:考察的是二次函数的移动法则:

    左加右减,上加下减。

    意思是,对一个二次函数(顶点式)

    f(x)=a(x+k)2+cf(x)=a\cdot (x+k)^2+c

    向左(右)移 kk 会增加(减少);

    向上(下)移 cc 会增加(减少)。

    于是上移代码如下:

    scanf("%lf",&k1);c+=k1;
    

    右移有些复杂,步骤如下:

    1. 将函数转为顶点式

    2. 在顶点式进行右移操作

    3. 顶点式转为一般式

    代码如下:

    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)

    这考察二次函数对称轴的转换和找特殊点。

    对一个二次函数

    f(x)=ax2+bx+cf(x)=a\cdot x^2+b\cdot x+c

    一定有且仅有一个对称轴:

    x=b2ax=-\frac{b}{2a}

    当函数图像关于点 P(x1,y1)P(x_1,y_1) 进行对称变换时,有以下 3 个结论:

    1. 开口方向会变;

    2. 对称轴会对直线 x=x1x=x_1 进行对称变换;

    3. 函数中所有点都会关于点 P(x1,y1)P(x_1,y_1) 进行对称变换。

    所以,指令 3 步骤如下:

    1. 计算原对称轴;

    2. 计算新对称轴;

    3. aa 变为 a-a

    4. 用新对称轴倒推得到 yy

    5. 因为当 x=0x=0 时,f(x)=cf(x)=c,所以原函数过点 Q(0,c)Q(0,c)QQ 点关于 PP 点进行对称变换,得到

    Q(2x1,2x2c)Q'(2\cdot x_1,2\cdot x_2-c)

    由结论 3 可知,QQ' 在新函数图像上。

    代码如下:

    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:求函数区间最值。

    前置知识:对于二次函数

    f(x)=ax2+bx+cf(x)=a\cdot x^2+b\cdot x+c

    他在闭区间 [k1,k2][k_1,k_2] 的最值只会出现在 k1k_1k2k_2 或顶点上。

    所以,先判断顶点是否在闭区间 [k1,k2][k_1,k_2] 上,再求最值。

    代码如下:

    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 之外最简单的了。

    题意即 ax2+bx+c=ux2+vx+wa\cdot x^2+b\cdot x+c=u\cdot x^2+v\cdot x+w

    用左式减去右式,得到

    (au)x2+(bv)x+(cw)=0(a-u)\cdot x^2+(b-v)\cdot x+(c-w)=0

    注意到 aua\ne u,问题转为求一元二次方程是否有解。

    即判别式 (bv)24(au)(cw)(b-v)^2-4(a-u)\cdot(c-w) 是否非负。

    代码如下:

    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;
    }
    

    完结撒花!

    • 1

    信息

    ID
    4017
    时间
    1000ms
    内存
    250MiB
    难度
    3
    标签
    递交数
    0
    已通过
    0
    上传者