2023 一元二次方程 · 方案一 照公式逐步写
统一符号、判判别式、提平方因子
正文
// CSP-J 2023 复赛 T3 · 一元二次方程
// 原题:https://oj.yecheng.tv/p/CSPJ2023C
// 题意:解 a*x^2 + b*x + c = 0,取较大的那个实根,按题目规定的格式输出;无实根输出 NO。
// 格式要点:有理数写成最简分数(分母为 1 就只写分子);
// 无理根写成「有理部分 + 系数 * sqrt(无平方因子部分)」,系数为 1 时省略。
//
// 方案一 · 一步一步照着公式写
// 第一步 统一符号:若 a < 0,把方程两边同乘 -1(a、b、c 全变号)。
// 这样 a 一定是正数,较大根就固定是 (-b + sqrt(delta)) / (2a),不用再分情况讨论。
// 第二步 算判别式 delta = b^2 - 4ac,小于 0 直接 NO。
// 第三步 开方:先判 delta 是不是完全平方数。
// · 是:根是有理数 (-b + sqrt(delta)) / (2a),约分后输出;
// · 否:把 delta 里的平方因子全部提出来,写成 delta = s^2 * r(r 不再含任何平方因子),
// 于是 根 = (-b)/(2a) + (s/(2a)) * sqrt(r),两部分各自约分后按格式拼起来。
// 开方一律用「先估后校」:sqrtl 估一下,再用 while 往回收一收,避免浮点误差。
#include <bits/stdc++.h>
using namespace std;
void printRational(long long p, long long q) {
if (q < 0) {
p = -p;
q = -q;
}
long long g = std::gcd(llabs(p), q);
p /= g;
q /= g;
if (q == 1) cout << p;
else cout << p << "/" << q;
}
long long isqrtFloor(long long x) {
long long s = (long long)sqrtl((long double)x);
while (s * s > x) s--;
while ((s + 1) * (s + 1) <= x) s++;
return s;
}
int main() {
freopen("uqe.in", "r", stdin);
freopen("uqe.out", "w", stdout);
int T, M;
cin >> T >> M;
while (T--) {
long long a, b, c;
cin >> a >> b >> c;
if (a < 0) {
a = -a;
b = -b;
c = -c;
}
long long delta = b * b - 4 * a * c;
if (delta < 0) {
cout << "NO\n";
continue;
}
long long p1 = -b; // 有理部分的分子
long long q1 = 2 * a; // 有理部分的分母(a > 0,所以分母为正)
long long sq = isqrtFloor(delta);
if (sq * sq == delta) { // 判别式是完全平方数,两个根都是有理数
printRational(p1 + sq, q1);
cout << "\n";
continue;
}
long long s = 1, r = delta; // 提平方因子:delta = s^2 * r
for (long long i = 2; i * i <= r; i++) {
while (r % (i * i) == 0) {
r /= i * i;
s *= i;
}
}
long long p2 = s, q2 = 2 * a;
long long g2 = std::gcd(p2, q2);
p2 /= g2;
q2 /= g2;
if (p1 != 0) {
printRational(p1, q1);
cout << "+";
}
if (p2 == 1 && q2 == 1) cout << "sqrt(" << r << ")";
else if (q2 == 1) cout << p2 << "*sqrt(" << r << ")";
else if (p2 == 1) cout << "sqrt(" << r << ")/" << q2;
else cout << p2 << "*sqrt(" << r << ")/" << q2;
cout << "\n";
}
return 0;
}
CSP-J 标程 · 复赛真题的其它内容
- 2019 数字游戏 · 方案一 逐字符统计
- 2019 数字游戏 · 方案二 二进制位运算
- 2020 优秀的拆分 · 方案一 贪心从大到小减
- 2020 优秀的拆分 · 方案二 直接看二进制位
- 2021 分糖果 · 方案一 枚举每个 k
- 2021 分糖果 · 方案二 看余数在哪一段
- 2022 乘方 · 方案一 边乘边判断
- 2022 乘方 · 方案二 快速幂加封顶
- 2023 小苹果 · 方案一 照规则真模拟
- 2023 小苹果 · 方案二 只盯住两个数字
- 2024 扑克牌 · 方案一 用集合去重
- 2024 扑克牌 · 方案二 二维布尔表
- 2025 拼数 · 方案一 收集后降序排序
- 2025 拼数 · 方案二 桶计数
- 2019 公交换乘 · 方案一 暴力匹配
- 2019 公交换乘 · 方案二 时间窗口优化
- 2020 直播获奖 · 方案一 每轮排序
- 2020 直播获奖 · 方案二 桶计数
- 2021 插入排序 · 方案一 每次真排一遍
- 2021 插入排序 · 方案二 增量维护有序表
- 2022 解密 · 方案一 二分求整数平方根
- 2022 解密 · 方案二 先估后校开方
- 2023 公路 · 方案一 朴素贪心
- 2023 公路 · 方案二 单调栈预处理
- 2024 地图探险 · 方案一 四方向分支写
- 2024 地图探险 · 方案二 方向数组
- 2025 座位 · 方案一 把座位表填出来
- 2025 座位 · 方案二 直接算排名
- 2019 纪念品 · 方案一 逐天完全背包
- 2019 纪念品 · 方案二 砍掉不赚钱物品
- 2020 表达式 · 方案一 每次重算后缀式
- 2020 表达式 · 方案二 建树加关键性传播
- 2021 网络连接 · 方案一 手写解析
- 2021 网络连接 · 方案二 读入后回拼校验
- 2022 逻辑表达式 · 方案一 递归分治
- 2022 逻辑表达式 · 方案二 递归下降
- 2023 一元二次方程 · 方案二 拆成小函数
- 2024 小木棍 · 方案一 先定位数再贪心
- 2024 小木棍 · 方案二 预处理最小数字表
- 2025 异或和 · 方案一 贪心能接就接
- 2025 异或和 · 方案二 动态规划加值域数组
- 2019 加工零件 · 方案一 递归加记忆化
- 2019 加工零件 · 方案二 奇偶最短路
- 2020 方格取数 · 方案一 深搜回溯
- 2020 方格取数 · 方案二 按列动态规划
- 2021 小熊的果篮 · 方案一 每轮扫一遍
- 2021 小熊的果篮 · 方案二 链表加有序集合
- 2022 上升点列 · 方案一 先只考虑不加点
- 2022 上升点列 · 方案二 二维动态规划
- 2023 旅游巴士 · 方案一 分层图加优先队列
- 2023 旅游巴士 · 方案二 状态压成一维
- 2024 接龙 · 方案一 按定义广搜
- 2024 接龙 · 方案二 滑动窗口逐轮推进
- 2025 多边形 · 方案一 枚举所有子集
- 2025 多边形 · 方案二 排序加计数 DP