洛谷 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;
}
posted @ 2024-07-23 19:41  MinimumSpanningTree  阅读(110)  评论(0)    收藏  举报