此题为CSP-J 2023 第三题一元二次方程。题目传送门
这道题是让求一个一元二次方程的较大实数根,并按照题目指定的方法进行输出。
首先需要先了解一下一元二次方程,题目中采用公式法来解方程。一元二次方程的一般形式为 ,系数为 , , 代入至 判断根的情况,如果有实数根则代入至 求出根。
一个有理数 将其约分至最简,如果可以整除输出p,否则输出p/q
解方程需要分为几步。首先判断根的情况,再判断根是有理数还是无理数,最后进行输出。
即 无实数根,输出NO
即 方程的根为 进行约分,根据有理数输出格式输出即可
即 方程的根为 , 由于 a 的正负不确定所以无法确定较大根是哪一种式子,所以需要在一开始就判断 a 的正负,如果 a 为负数,那么就将系数全部取反(这样不影响结果)。这样 便是较大根。接下来判断 是否为有理数,有理数则约分输出;无理数则需要将式子转化为 ,首先可以知道 ,然后将 分解为 的结构,然后开出 ,所以 。
#include<bits/stdc++.h>using namespace std;int T,M,a,b,c,t,fz,fm,st,x,r;void YueFen() // 约分函数{ int flag=0; if(fz<0) flag=1,fz=-fz;//如果分子是负数进行取反,避免约分后符号位出错 int temp=__gcd(fz,fm);//求最大公约数 fz/=temp,fm/=temp; if(flag) fz=-fz;//还原符号位}void x2r() // 用于将 delta 分解为x^2*r{ for(int i=sqrt(t);i>=1;i--)// x最大从 根号delta开始 从大往小枚举,确保第一个r是最简的 { int temp=t/(i*i); if(temp*(i*i)==t){ x=i,r=temp; return; } }}int main(){ cin>>T>>M; while(T--) { cin>>a>>b>>c; if(a<0) a=-a,b=-b,c=-c;//如果a为负数,全部取反,确保式子结果不变 t=b*b-4*a*c; if(t<0)//delta < 0 无解 { cout<<"NO"<<endl; } else if(t==0)//delta = 0 两个相等的实数根 x=-b/2a { fz=-b,fm=2*a; YueFen(); if(fm==1) cout<<fz<<endl; else cout<<fz<<'/'<<fm<<endl; } else//delta > 0 方程两个不相等的实数根,计算较大的 { st=sqrt(t); if(st*st==t)//判断 根号delta是否是有理数 { fz=-b+st,fm=2*a; YueFen(); if(fm==1) cout<<fz<<endl; else cout<<fz<<'/'<<fm<<endl; } else { if(b!=0)//计算q1 { fz=-b,fm=2*a; YueFen(); if(fm==1) cout<<fz<<'+'; else cout<<fz<<'/'<<fm<<'+'; } x2r();//用于将 delta 分解为x^2*r,开出x于2a进行约分的出q2,同时求出r fz=x,fm=2*a; YueFen(); if(fz==fm)//输出 cout<<"sqrt("<<r<<')'<<endl; else if(fm==1) cout<<fz<<"*sqrt("<<r<<')'<<endl; else if(fz==1) cout<<"sqrt("<<r<<")/"<<fm<<endl; else cout<<fz<<"*sqrt("<<r<<")/"<<fm<<endl; } } } return 0;}