CSP-J(入门级)2023年T3 一元二次方程
众所周知,对一元二次方程ax2bxc0a0Δb2−4acΔ0Δ≥0x122a−b±Δx2x10Δ12−4×1×1−30x2−2x10x121x2−3x20x11x22在题面描述中a和b的最大公因数使用gcdab表示。例如12和18的最大公因数是6,即gcd12186。
[CSP-J 2023] 一元二次方程【民间数据】
题目背景
众所周知,对一元二次方程 a x 2 + b x + c = 0 , ( a ≠ 0 ) ax ^ 2 + bx + c = 0, (a \neq 0) ax2+bx+c=0,(a=0),可以用以下方式求实数解:
- 计算
Δ
=
b
2
−
4
a
c
\Delta = b ^ 2 - 4ac
Δ=b2−4ac,则:
- 若 Δ < 0 \Delta < 0 Δ<0,则该一元二次方程无实数解。
- 否则 Δ ≥ 0 \Delta \geq 0 Δ≥0,此时该一元二次方程有两个实数解 x 1 , 2 = − b ± Δ 2 a x _ {1, 2} = \frac{-b \pm \sqrt \Delta}{2a} x1,2=2a−b±Δ。
例如:
- x 2 + x + 1 = 0 x ^ 2 + x + 1 = 0 x2+x+1=0 无实数解,因为 Δ = 1 2 − 4 × 1 × 1 = − 3 < 0 \Delta = 1 ^ 2 - 4 \times 1 \times 1 = -3 < 0 Δ=12−4×1×1=−3<0。
- x 2 − 2 x + 1 = 0 x ^ 2 - 2x + 1 = 0 x2−2x+1=0 有两相等实数解 x 1 , 2 = 1 x _ {1, 2} = 1 x1,2=1。
- x 2 − 3 x + 2 = 0 x ^ 2 - 3x + 2 = 0 x2−3x+2=0 有两互异实数解 x 1 = 1 , x 2 = 2 x _ 1 = 1, x _ 2 = 2 x1=1,x2=2。
在题面描述中 a a a 和 b b b 的最大公因数使用 gcd ( a , b ) \gcd(a, b) gcd(a,b) 表示。例如 12 12 12 和 18 18 18 的最大公因数是 6 6 6,即 gcd ( 12 , 18 ) = 6 \gcd(12, 18) = 6 gcd(12,18)=6。
题目描述
现在给定一个一元二次方程的系数 a , b , c a, b, c a,b,c,其中 a , b , c a, b, c a,b,c 均为整数且 a ≠ 0 a \neq 0 a=0。你需要判断一元二次方程 a x 2 + b x + c = 0 a x ^ 2 + bx + c = 0 ax2+bx+c=0 是否有实数解,并按要求的格式输出。
在本题中输出有理数 v v v 时须遵循以下规则:
-
由有理数的定义,存在唯一的两个整数 p p p 和 q q q,满足 q > 0 q > 0 q>0, gcd ( p , q ) = 1 \gcd(p, q) = 1 gcd(p,q)=1 且 v = p q v = \frac pq v=qp。
-
若 q = 1 q = 1 q=1,则输出
{p}
,否则输出{p}/{q}
,其中{n}
代表整数 n n n 的值; -
例如:
- 当
v
=
−
0.5
v = -0.5
v=−0.5 时,
p
p
p 和
q
q
q 的值分别为
−
1
-1
−1 和
2
2
2,则应输出
-1/2
; - 当
v
=
0
v = 0
v=0 时,
p
p
p 和
q
q
q 的值分别为
0
0
0 和
1
1
1,则应输出
0
。
- 当
v
=
−
0.5
v = -0.5
v=−0.5 时,
p
p
p 和
q
q
q 的值分别为
−
1
-1
−1 和
2
2
2,则应输出
对于方程的求解,分两种情况讨论:
-
若 Δ = b 2 − 4 a c < 0 \Delta = b ^ 2 - 4ac < 0 Δ=b2−4ac<0,则表明方程无实数解,此时你应当输出
NO
; -
否则 Δ ≥ 0 \Delta \geq 0 Δ≥0,此时方程有两解(可能相等),记其中较大者为 x x x,则:
-
若 x x x 为有理数,则按有理数的格式输出 x x x。
-
否则根据上文公式, x x x 可以被唯一表示为 x = q 1 + q 2 r x = q _ 1 + q _ 2 \sqrt r x=q1+q2r 的形式,其中:
- q 1 , q 2 q _ 1, q _ 2 q1,q2 为有理数,且 q 2 > 0 q _ 2 > 0 q2>0;
- r r r 为正整数且 r > 1 r > 1 r>1,且不存在正整数 d > 1 d > 1 d>1 使 d 2 ∣ r d ^ 2 \mid r d2∣r(即 r r r 不应是 d 2 d ^ 2 d2 的倍数);
此时:
- 若
q
1
≠
0
q _ 1 \neq 0
q1=0,则按有理数的格式输出
q
1
q _ 1
q1,并再输出一个加号
+
; - 否则跳过这一步输出;
随后:
- 若
q
2
=
1
q _ 2 = 1
q2=1,则输出
sqrt({r})
; - 否则若
q
2
q _ 2
q2 为整数,则输出
{q2}*sqrt({r})
; - 否则若
q
3
=
1
q
2
q _ 3 = \frac 1{q _ 2}
q3=q21 为整数,则输出
sqrt({r})/{q3}
; - 否则可以证明存在唯一整数
c
,
d
c, d
c,d 满足
c
,
d
>
1
,
gcd
(
c
,
d
)
=
1
c, d > 1, \gcd(c, d) = 1
c,d>1,gcd(c,d)=1 且
q
2
=
c
d
q _ 2 = \frac cd
q2=dc,此时输出
{c}*sqrt({r})/{d}
;
上述表示中
{n}
代表整数{n}
的值,详见样例。如果方程有实数解,则按要求的格式输出两个实数解中的较大者。否则若方程没有实数解,则输出
NO
。 -
输入格式
输入的第一行包含两个正整数 T , M T, M T,M,分别表示方程数和系数的绝对值上限。
接下来 T T T 行,每行包含三个整数 a , b , c a, b, c a,b,c。
输出格式
输出 T T T 行,每行包含一个字符串,表示对应询问的答案,格式如题面所述。
每行输出的字符串中间不应包含任何空格。
样例 #1
样例输入 #1
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
1
NO
1
-1
-1/2
12*sqrt(3)
3/2+sqrt(5)/2
1+sqrt(2)/2
-7/2+3*sqrt(5)/2
提示
【样例 #2】
见附件中的 uqe/uqe2.in
与 uqe/uqe2.ans
。
【数据范围】
对于所有数据有: 1 ≤ T ≤ 5000 1 \leq T \leq 5000 1≤T≤5000, 1 ≤ M ≤ 1 0 3 1 \leq M \leq 10 ^ 3 1≤M≤103, ∣ a ∣ , ∣ b ∣ , ∣ c ∣ ≤ M |a|,|b|,|c| \leq M ∣a∣,∣b∣,∣c∣≤M, a ≠ 0 a \neq 0 a=0。
测试点编号 | M ≤ M \leq M≤ | 特殊性质 A | 特殊性质 B | 特殊性质 C |
---|---|---|---|---|
1 1 1 | 1 1 1 | 是 | 是 | 是 |
2 2 2 | 20 20 20 | 否 | 否 | 否 |
3 3 3 | 1 0 3 10 ^ 3 103 | 是 | 否 | 是 |
4 4 4 | 1 0 3 10 ^ 3 103 | 是 | 否 | 否 |
5 5 5 | 1 0 3 10 ^ 3 103 | 否 | 是 | 是 |
6 6 6 | 1 0 3 10 ^ 3 103 | 否 | 是 | 否 |
7 , 8 7, 8 7,8 | 1 0 3 10 ^ 3 103 | 否 | 否 | 是 |
9 , 10 9, 10 9,10 | 1 0 3 10 ^ 3 103 | 否 | 否 | 否 |
其中:
- 特殊性质 A:保证 b = 0 b = 0 b=0;
- 特殊性质 B:保证 c = 0 c = 0 c=0;
- 特殊性质 C:如果方程有解,那么方程的两个解都是整数。
【解析】
考虑特殊性质C,轻松拿50分。
详见代码:
#include <bits/stdc++.h>
using namespace std;
int T,M;
main() {
scanf("%d%d",&T,&M);
while (T--){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
int dt=b*b-4*a*c;
if (dt<0){
printf("NO\n");
continue;
}
int p1=(-b+sqrt(dt))/a/2;
int p2=(-b-sqrt(dt))/a/2;
int p=max(p1,p2);
printf("%d\n",p);
}
return 0;
}
感谢佛山的梁老师提供的正解
#include <bits/stdc++.h>
using namespace std;
int a, b, c, T, M, fz, fm;
int gcd(int x, int y) {
if (x % y == 0) return y;
return gcd(y, x%y);
}
int main() {
scanf("%d%d", &T, &M);
while(T--) {
scanf("%d%d%d", &a, &b, &c);
int gen = b * b - 4 * a * c;
if (gen < 0) {
printf("NO\n");
} else if (sqrt(gen) == int(sqrt(gen))) {
fz = -b + sqrt(gen) *(a > 0 ? 1 : -1);
fm = 2 * a;
if (fz % fm == 0) {
printf("%d\n", fz/fm);
} else {
if(fz*fm<0) printf("-");
int k = gcd(abs(fz),abs(fm));
printf("%d/%d\n",abs(fz)/k, abs(fm)/k);
}
} else {
if (b != 0) {
fz = -b;
fm = 2 * a;
if (fz % fm == 0) {
printf("%d+",fz/fm);
} else {
if(fz*fm<0) printf("-");
int k = gcd(abs(fz),abs(fm));
printf("%d/%d+",abs(fz)/k, abs(fm)/k);
}
}
int ma = 1;
for (int i = 2; i*i <= gen; i++) {
while(gen % (i*i) == 0) {
ma *= i;
gen /= i* i;
}
}
fz = ma;
fm = abs(2 * a);
if (fz % fm == 0) {
if (fz != fm) printf("%d*",fz/fm);
printf("sqrt(%d)\n",gen);
} else {
int k = gcd(abs(fz),abs(fm));
if (fz/k!=1) printf("%d*",fz/k);
printf("sqrt(%d)/%d\n",gen,fm/k);
}
}
}
return 0;
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)