TB椰程 TypeBuddy 打字搭子

2023 一元二次方程 · 方案二 拆成小函数

CSP-J 标程 · 复赛真题 · 代码 · cpp · 难度 4/5 · 共 2228 字

有理数输出和根号输出各抽成一个函数

  • 2023
  • 数学

正文

// CSP-J 2023 复赛 T3 · 一元二次方程(方案二)
// 原题:https://oj.yecheng.tv/p/CSPJ2023C
//
// 方案二 · 把「有理数输出」和「根号部分输出」各抽成一个函数
// 数学思路和方案一一模一样,区别只在代码组织:
//   printRational(p, q) 负责约分并按「分母为 1 就省略」输出;
//   printSqrtPart(p, q, r) 负责处理系数 p/q 的四种写法:
//     系数是 1       -> sqrt(r)
//     系数是整数 k   -> k*sqrt(r)
//     系数是 1/k     -> sqrt(r)/k
//     系数是 c/d     -> c*sqrt(r)/d
//   solveOne() 只管走流程:统一符号、算判别式、开方、分类输出。
// 分函数的好处是每一块都能单独检查,改格式时也不用在大段代码里翻。

#include <bits/stdc++.h>
using namespace std;

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;
}

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;
}

// 输出 (p/q) * sqrt(r),p 和 q 已经互质且都为正
void printSqrtPart(long long p, long long q, long long r) {
    if (p == 1 && q == 1) cout << "sqrt(" << r << ")";
    else if (q == 1) cout << p << "*sqrt(" << r << ")";
    else if (p == 1) cout << "sqrt(" << r << ")/" << q;
    else cout << p << "*sqrt(" << r << ")/" << q;
}

void solveOne() {
    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";
        return;
    }
    long long p1 = -b, q1 = 2 * a;
    long long sq = isqrtFloor(delta);
    if (sq * sq == delta) {
        printRational(p1 + sq, q1);
        cout << "\n";
        return;
    }
    long long s = 1, r = delta;
    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 << "+";
    }
    printSqrtPart(p2, q2, r);
    cout << "\n";
}

int main() {
    freopen("uqe.in", "r", stdin);
    freopen("uqe.out", "w", stdout);

    int T, M;
    cin >> T >> M;
    while (T--) solveOne();
    return 0;
}

CSP-J 标程 · 复赛真题的其它内容

打字首页 · 词库画廊 · 编程打字 · 指法入门 · 天梯榜 · 数据分析 · 班级课堂 · 关于我们
椰程 TypeBuddy 打字搭子 —— 键盘指法练习 · 单词记忆 · 班级课堂 · 在线 PK