【题目描述】
众所周知,对一元二次方程 ax2+bx+c=0,(a≠0)
,可以用以下方式求实数解:
∙
计算 Δ=b2−4ac
,则:
-
若 Δ<0
,则该一元二次方程无实数解。 -
否则 Δ≥0
,此时该一元二次方程有两个实数解 x1,2=−b±Δ√2a
。
例如:
∙x2+x+1=0
无实数解,因为 Δ=12−4×1×1=−3<0
。
∙x2−2x+1=0
有两相等实数解 x1,2=1
。
∙x2−3x+2=0
有两互异实数解 x1=1,x2=2
。
在题面描述中 a
和 b
的最大公因数使用 gcd(a,b)
表示。例如 12
和 18
的最大公因数是 6
,即 gcd(12,18)=6
。
现在给定一个一元二次方程的系数 a,b,c
,其中 a,b,c
均为整数且 a≠0
。你需要判断一元二次方程 ax2+bx+c=0
是否有实数解,并按要求的格式输出。
在本题中输出有理数 v
时须遵循以下规则:
∙
由有理数的定义,存在唯一的两个整数 p
和 q
,满足 q>0
,gcd(p,q)=1
且 v=pq
。
∙
若 q=1
,则输出 {p},否则输出 {p}/{q},其中 {n} 代表整数 n
的值;
∙
例如:
∙
当 v=−0.5
时,p
和 q
的值分别为 −1
和 2
,则应输出 -1/2;
∙
当 v=0
时,p
和 q
的值分别为 0
和 1
,则应输出 0。
对于方程的求解,分两种情况讨论:
-
若 Δ=b2−4ac<0
,则表明方程无实数解,此时你应当输出 NO; -
否则 Δ≥0
,此时方程有两解(可能相等),记其中较大者为 x
,则:
(1). 若 x
为有理数,则按有理数的格式输出 x
。
(2). 否则根据上文公式,x
可以被唯一表示为 x=q1+q2r√
的形式,其中:
∙q1,q2
为有理数,且 q2>0
;
∙r
为正整数且 r>1
,且不存在正整数 d>1
使 d2∣r
(即 r
不应是 d2
的倍数);
此时:
-
若 q1≠0
,则按有理数的格式输出 q1
,并再输出一个加号 +; -
否则跳过这一步输出;
随后:
-
若 q2=1
,则输出 sqrt({r}); -
否则若 q2
为整数,则输出 {q2}*sqrt({r}); -
否则若 q3=1q2
为整数,则输出 sqrt({r})/{q3}; -
否则可以证明存在唯一整数 c,d
满足 c,d>1,gcd(c,d)=1
且 q2=cd
,此时输出{c}*sqrt({r})/{d};
上述表示中 {n} 代表整数 {n} 的值,详见样例。
如果方程有实数解,则按要求的格式输出两个实数解中的较大者。否则若方程没有实数解,则输出 NO。
【输入】
输入的第一行包含两个正整数 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
12sqrt(3)
3/2+sqrt(5)/2
1+sqrt(2)/2
-7/2+3sqrt(5)/2
【提示】
【数据范围】
对于所有数据有:1≤T≤5000
,1≤M≤103
,∣a∣,∣b∣,∣c∣≤M
,a≠0
。
测试点编号 M≤ 特殊性质 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:如果方程有解,那么方程的两个解都是整数。
没必说大模拟,撮合撮合还能用。
#include<bits/stdc++.h>
using namespace std;
int t, a, b, c, up;
int main() {
cin >> t >> up;
while (t--) {
cin >> a >> b >> c;
int derta = b * b - 4 * a * c;
if (derta < 0) {
cout << "NO\n";
continue;
}
if ((int)sqrt(derta) * (int)sqrt(derta) == derta) {
int z, m = 2 * a;
if (a < 0) {
z = -sqrt(derta) - b;
} else {
z = sqrt(derta) - b;
}
if (z > 0 && m < 0) {
z = -z, m = -m;
}
if (z < 0 && m < 0) {
z = -z, m = -m;
}
if (z % m == 0) {
cout << z / m;
} else {
int g = __gcd(abs(m), abs(z));
cout << z / g << "/" << m / g;
}
} else {
int uz = -b, um = 2 * a, z = derta;
if (uz != 0) {
if (uz > 0 && um < 0) {
uz = -uz, um = -um;
}
if (uz < 0 && um < 0) {
uz = -uz, um = -um;
}
if (uz % um == 0) {
cout << uz / um;
} else {
int g = __gcd(abs(um), abs(uz));
cout << uz / g << "/" << um / g;
}
cout << "+";
}
int q2 = 1;
for (int i = sqrt(derta); i >= 2; i--) {
if (z % (i * i) == 0) {
q2 = i;
z /= i * i;
break;
}
}
int g = __gcd(abs(a) * 2, q2);
a = abs(a) * 2 / g, q2 /= g;
if (q2 == 1 && a == 1) {
cout << "sqrt(" << z << ")";
} else if (q2 == 1) {
cout << "sqrt(" << z << ")/" << a;
} else if (q2 % a == 0) {
cout << q2 / a << "*sqrt(" << z << ")";
} else {
cout << q2 << "*sqrt(" << z << ")/" << a;
}
}
cout << "\n";
}
return 0;
}