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

思路

大模拟,按照题意模拟即可。

首先按照 Δ\Delta 的取值分为 33 类:

  1. Δ<0\Delta < 0

  2. Δ=0\Delta = 0

  3. Δ>0\Delta > 0

对于第 1 种情况,根据题意,输出 NO

对于第 2 种情况,原方程只会有一个解为 b2a\frac{-b}{2a},求一个 gcd\gcd 约分即可。

对于第 3 种情况,原方程会有两个解 b±×Δ2a\frac{-b \pm \times \sqrt{\Delta}}{2a},此时我们可以得到此时取 - 更优,还是取 ++ 更优。在这里我们定义 w=1/1w = -1/1 表示在原方程中取 - / ++ 更优。

然后化简 Δ\sqrt{\Delta} 为一个 pair t,表示 t1t2t_1 \sqrt{t_2} 并且满足 t2\sqrt{t_2} 最简。

t2t_2 的取值也分为 22 种情况:

  1. t2=1t_2 = 1

  2. t21t_2 \neq 1

对于第 1 种情况,答案为 b+w×t12a\frac{-b + w \times t_1}{2a}

对于第 2 种情况,由于 b2a\frac{-b}{2a} 有可能为 00,所以需要单独判断一下即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <bits/stdc++.h>  
#define fst first
#define snd second
#define re register
#define int long long
#define double long double

using namespace std;

typedef pair<int,int> pii;
const double eps = 1e-5;
int T,lim,a,b,c;

inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 1) + (r << 3) + (c ^ 48);
c = getchar();
}
return r * w;
}

inline int gcd(int a,int b){
if (!b) return a;
return gcd(b,a % b);
}

inline int qmi(int a,int b){
int res = 1;
while (b){
if (b & 1) res *= a;
a *= a;
b >>= 1;
}
return res;
}

inline void print_num(int x,int y,bool f){
if (!x){
if (f) printf("0");
return;
}
int w = 1;
if (x < 0){
x = -x;
w *= (-1);
}
if (y < 0){
y = -y;
w *= (-1);
}
int g = gcd(x,y);
x /= g;
y /= g;
if (!~w) printf("-");
if (y == 1) printf("%lld",x);
else printf("%lld/%lld",x,y);
}

inline pii get_sqrt(int x){
pii res = {1,1};
for (re int i = 2;i * i <= x;i++){
if (x % i == 0){
int cnt = 0;
while (x % i == 0){
cnt++;
x /= i;
}
res.fst *= qmi(i,cnt / 2);
res.snd *= max(1ll,i * (cnt % 2));
}
}
if (x != 1) res.snd *= x;
return res;
}

inline pii get_div(int w,bool ok,int x,int y){
if (x < 0){
x = -x;
w *= (-1);
}
if (y < 0){
y = -y;
w *= (-1);
}
int g = gcd(x,y);
x /= g;
y /= g;
if (ok){
if (~w) printf("+");
else printf("-");
}
return {x,y};
}

inline void solve(){
int w;
a = read();
b = read();
c = read();
int del = b * b - 4 * a * c;
if (del < 0){
puts("NO");
return;
}
if (!del){
print_num(-b,2 * a,true);
puts("");
return;
}
double sdel = sqrtl(del);
if ((1.0 * (-1.0 * b - sdel) / (2.0 * a)) > (1.0 * (-1.0 * b + sdel) / (2.0 * a))) w = -1;
else w = 1;
pii t = get_sqrt(del);
if (t.snd == 1){
int s = -b + w * t.fst;
int m = 2 * a;
print_num(s,m,true);
}
else{
double div = fabs((-b) / (2.0 * a));
bool ok;
print_num(-b,2 * a,false);
if (div > eps) ok = true;
else ok = false;
pii res = get_div(w,ok,t.fst,2 * a);
if (res.fst != 1) printf("%lld*",res.fst);
printf("sqrt(%lld)",t.snd);
if (res.snd != 1) printf("/%lld",res.snd);
}
puts("");
}

signed main(){
T = read();
lim = read();
while (T--) solve();
return 0;
}

P9750 [CSP-J 2023] 一元二次方程
http://watersun.top/[题解]P9750 [CSP-J 2023] 一元二次方程/
作者
WaterSun
发布于
2023年10月29日
许可协议