洛谷 P9750 [CSP-J 2023] 一元二次方程 题解
这是一道数学+模拟题。
方程的解可以分成两种情况:有理数和无理数。所以我们可以分成这两种情况来计算方程的解。
由于公式 \(\frac{-b\pm\sqrt\Delta}{2a}\) 只有 \(\sqrt\Delta\) 部分会产生无理数,所以我们可以通过判断 \(\sqrt\Delta\) 是有理数还是无理数得出解是有理数还是无理数。
如何判断 \(\sqrt\Delta\) 是有理数还是无理数?可以使用 \(sqrt\) 函数,使用一个 int 变量 \(sqrt\_floor\) 存储 \(sqrt(\sqrt\Delta)\),再判断 \(sqrt\_floor\times sqrt\_floor\) 是否等于 \(\Delta\),如果等于说明方程的解是有理数,否则是无理数。
关于分数,有几个需要注意的点:
-
当分子和分母都是负数时,分子和分母都取它们的相反数。
-
当分子不是负数但分母是负数时,把分母的负号给分子(分子和分母都取它们的相反数)。
-
当分母等于 \(1\) 时,不需要输出分子和分数线。
有理数的部分:
先存储 \(\frac{-b+\sqrt\Delta}{2a}\) 和 \(\frac{-b-\sqrt\Delta}{2a}\) 两个解,约分、处理负号后,对两个分数作比较,输出较大的分数。
无理数的部分:
先处理 \(\frac{-b}{2a}\) ,再输出加号。
接下来的部分和有理数一样,但是注意分子存储的是 \(sqrt\) 格式。
由于 \(\sqrt{a\times b}=\sqrt a\times\sqrt b\) ,我们还可以对这个无理数化简。
我们可以枚举完全平方数,如果能被 \(\sqrt\Delta\) 整除,则 \(\sqrt\Delta\) 除以这个平方数, \(x\times=\) 这个平方数的平方根,最后再以 {c}*sqrt({r})/{d} 的格式输出。
根据数据范围,我们只需要枚举大概 \(1^2\sim3000^2\) 的完全平方数。
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int t,m,a,b,c,s,sqrt_floor,fm1,fz1,fm2,fz2,fzfm_gcd,x,r;
int gcd1(int a1,int a2)
{
if(a1%a2==0) return a2;
return gcd1(a2,a1%a2);
}
int main()
{
scanf("%d%d",&t,&m);
//for(int i=1;i<=3000;i++) pf[i]=i*i;
while(t--)
{
scanf("%d%d%d",&a,&b,&c);
s=b*b-4*a*c;
if(s<0)
{
printf("NO\n");
continue;
}
sqrt_floor=sqrt(s);
if(s==sqrt_floor*sqrt_floor)//解是有理数
{
fz1=-b+sqrt_floor,fm1=a*2;
fz2=-b-sqrt_floor,fm2=a*2;
//处理负号
if(fz1<0&&fm1<0) fz1=-fz1,fm1=-fm1;
if(fm1<0) fz1=-fz1,fm1=-fm1;
if(fz2<0&&fm2<0) fz2=-fz2,fm2=-fm2;
if(fm2<0) fz2=-fz2,fm2=-fm2;
//约分
fzfm_gcd=gcd1(abs(fz1),abs(fm1));
if(fzfm_gcd!=1) fz1/=fzfm_gcd,fm1/=fzfm_gcd;
fzfm_gcd=gcd1(abs(fz2),abs(fm2));
if(fzfm_gcd!=1) fz2/=fzfm_gcd,fm2/=fzfm_gcd;
if(fm2*fz1>=fm1*fz2)
{
printf("%d",fz1);
if(fm1!=1) printf("/%d",fm1);
}
else
{
printf("%d",fz2);
if(fm2!=1) printf("/%d",fm2);
}
printf("\n");
}
else//解是无理数
{
fz1=-b,fm1=2*a;
//处理负号
if(fz1<0&&fm1<0) fz1=-fz1,fm1=-fm1;
if(fm1<0) fz1=-fz1,fm1=-fm1;
fzfm_gcd=gcd1(abs(fz1),abs(fm1));
if(fzfm_gcd!=1) fz1/=fzfm_gcd,fm1/=fzfm_gcd;
if(fm1!=0&&fz1!=0)//输出
{
printf("%d",fz1);
if(fm1!=1) printf("/%d",fm1);
printf("+");
}
x=1,r=s;
for(int i=2;i<=3000;i++)//枚举完全平方数
{
while(r%(i*i)==0) r/=(i*i),x*=i;
}
fz1=x,fm1=2*a;
//处理负号
if(fz1<0) fz1=-fz1;
if(fm1<0) fm1=-fm1;
fzfm_gcd=gcd1(fz1,fm1);
if(fzfm_gcd!=1) fz1/=fzfm_gcd,fm1/=fzfm_gcd;
if(fz1!=1) printf("%d*",fz1);
printf("sqrt(%d)",r);
if(fm1!=1) printf("/%d",fm1);
printf("\n");
}
}
return 0;
}

浙公网安备 33010602011771号