[CSP-J 2023] 一元二次方程

40次阅读
没有评论

共计 2626 个字符,预计需要花费 7 分钟才能阅读完成。

题目

众所周知,对于一元二次方程 ax^2+bx+c=0 (a\ne0),可以用以下方式求实数解:
- 计算 \Delta=b^2-4ac
- 若 \Delta<0,则该一元二次方程无实数解。
- 否则 \Delta\ge0,此时该一元二次方程有两个实数解 x_{1,2} = \frac {-b \pm \sqrt \Delta} {2a}
其中,\sqrt \Delta 表示 \Delta 的算术平方根,即使得 s^2=\Delta 的唯一非负实数。
特别地,当 \Delta=0时,这两个实数解相等,当 \Delta>0 时,这两个实数解互异。

例如:
- x^2+x+1=0 无实数解,因为 \Delta=1^2-4\times1\times1=-3<0
- x^2-2x+1=0 有两相等实数解 x_{1,2}=1
- x^2-3x+2=0 有两互异实数解 x_1=1, x_2=2

在题面描述中 ab 的最大公因数使用 \gcd(a,b) 表示。例如 1218 的最大公因数是 6,即 \gcd(12,18)=6

现在给定一个一元二次方程的系数 a, b, c,其中 a, b, c 均为整数且 a\ne0。你需要判断 ax^2+bx+c=0 是否有实数解,并按要求格式输出。

在本题中输出有理数 v 时需遵循以下规则:
- 由有理数的定义,存在唯一的两个整数 pq,满足 q>0, \gcd(p,q)=1v=\frac p q
- 若 q=1则输出 {p},否则输出{p}/{q},其中{n} 代表整数 n 的值。;
- 例如:
- 当 v=-0.5 时,pq 的值分别为 -12,则应输出-1/2
- 当 v=0 时,pq 的值分别为 01,则应输出0

对方程的求解,分两种情况讨论:
1. 若方程无实数解,你应该输出NO

  1. 否则方程有两解,记其中较大者为 x,则:
    1. x 为有理数,则按有理数的格式输出 x

    2. 否则根据上文公式,x 可以被 唯一的 表示为 x=q_1+q_2\sqrt r 的形式,其中:

    • $q_1, q_2$ 为有理数,且 $q_2>0$;
    • $r$ 为正整数且 $r>1$,且不存在正整数 $d>1$ 使 $d^2|r$(即 $r$ 不应是 $d^2$ 的倍数)。

    此时:

    1. q_1\ne0,则按有理数的格式输出 q_1,并输出一个加号+
    2. 否则跳过这一步输出。

    随后:

    1. q_2=1,则输出sqrt({r})
    2. 否则若 q_2 为整数,则输出{q2}*sqrt({r})
    3. 否则若 q_3=\frac 1 {q_2} 为整数,则输出sqrt({r})/{q3}
    4. 否则可以证明存在唯一整数 c, d 满足 c,d>1, \gcd(c,d)=1q_2=\frac c d,此时输出{c}*sqrt({r})/{d}

输入描述

输入的第一行包含两个正整数 T, M,分别表示方程数和系数的绝对值上限。

接下来 T 行,每行包含三个整数 a, b, c

输出描述

输出 T 行,每行包含一个字符串,表示对应询问的答案,格式如题面所述。

每行输出的字符串中间不应包含任何空格。

样例

输入

9 1000
1 -1 0
-1 -1 -1
1 -2 1
1 5 4
4 4 1
1 0 -432
1 -3 1
2 -4 1
1 7 1

输出

1
NO
1
-1
-1/2
12*sqrt(3)
3/2+sqrt(5)/2
1+sqrt(2)/2
-7/2+3*sqrt(5)/2

数据范围

对于所有数据有:1\le50001\le M\le10^3|a|,|b|,|c|\le Ma\ne 0

测试点编号$M\le$特殊性质 A特殊性质 B特殊性质 C
$1$$1$
$2$20×××
$3$$10^3$×
$4$$10^3$××
$5$$10^3$×
$6$$10^3$××
$7,8$$10^3$××
$9,10$$10^3$×××

其中:

  • 特殊性质 A:保证 b=0
  • 特殊性质 B:保证 c=0
  • 特殊性质 C:如果方程有解,那么方程的两个解都是整数。

答案

#pragma GCC optimize(3)
#include <iostream>
#include <cmath>
using namespace std;

long long t, m, a, b, c, d, p, q, g, sg, e, i;

long long gcd(long long x, long long y){if(y==0) return x;
    return gcd(y, x%y);
}

int main(){ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> t >> m;

    while(t--){
        cin >> a >> b >> c;
        d = b*b - 4*a*c;

        p=-b, q=2*a;
        if(d<0){cout << "NO" << endl;}
        else if(d==0){g = gcd(abs(p), abs(q));
            p/=g, q/=g;

            if(q<0) q=-q, p=-p;
            if(q==1) cout << p << endl;
            else cout << p << "/" << q << endl;
        }
        else{sg = (long long)sqrt(d);
            if(sg*sg==d){if(q>0) p+=sg;
                else p-=sg;
                g = gcd(abs(p), abs(q));
                p/=g, q/=g;
                if(q<0) q=-q, p=-p;
                if(q==1) cout << p << endl;
                else cout << p << "/" << q << endl;
            }
            else{g = gcd(abs(q), abs(p));
                p/=g, q/=g;
                if(q<0) p=-p, q=-q;
                if(p!=0){if(q==1) cout << p;
                    else cout << p << "/" << q;
                    cout << "+";
                }
                q = abs(2*a);
                p = 1;
                e = 0;
                for(i=sg;i>=1;i--) if(d%(i*i)==0) {
                    p *= i;
                    e = d / (i*i);
                    break;
                }
                g = gcd(abs(q), abs(p));
                p/=g, q/=g;
                if(q<0) p=-p, q=-q;
                if(p==q) cout << "sqrt(" << e << ")" << endl;
                else if(q==1) cout << p << "*sqrt(" << e << ")" << endl;
                else if(p==1) cout << "sqrt(" << e << ")/" << q << endl;
                else cout << p << "*sqrt(" << e << ")/" << q << endl;
            }
        }
    }
}

解析

题目讲的很清楚,就根据题目讲的硬判。

正文完
 0
元素
版权声明:本站原创文章,由 元素 于2024-10-25发表,共计2626字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码