1 条题解

  • 0
    @ 2026-10-26 13:00:02

    思路与算法

    令目标值为v,则F(x)≤v等价于所有二次函数都≤v。a>0时解二次不等式,得到两个实根之间的闭区间;判别式为负则无解。a=0时按一次不等式求半直线,b也为0时判断常量是否≤v。将所有区间与[0,1000]求交,非空即v可行。可行性随v单调不减,于是对v进行100次二分并输出可行上界。

    正确性说明

    对a>0的开口向上抛物线,不等式成立区域恰好为根间区间;一次及常量情况分别单独处理,因此每条约束都被准确表示。全部交集非空当且仅当存在同一个x满足所有约束,也就当且仅当min F≤v。这证明二分判定的单调性与等价性。初始下界-5005000不大于任何允许函数在区间内的值,上界100005005000大于区间内所有函数值,100次迭代使数值区间足够窄。

    复杂度

    每轮O(n)个常数次求根与区间交,共固定100轮,时间O(100n)。输入系数数组初始化O(n),空间O(n),每轮只需常量工作空间。使用long double并对最终接近0的值规范化,按四位小数输出。数据n≤10000、T<10,不保存多组数据。

    易错点

    必须处理a=0及a=b=0,不能直接除以2a。区间交从[0,1000]开始,最优值可能在端点,也可能为负数。原目录缺少独立三分知识节点,本解实际使用答案二分与二次不等式,正式映射对应实际方法。独立答案枚举各曲线顶点与两两交点,并以60位Decimal取上包络最小值。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        int T;
        cin >> T;
        cout << fixed << setprecision(4);
        while (T--) {
            int n;
            cin >> n;
            vector<array<long double, 3>> v(n);
            for (auto &f : v)
                cin >> f[0] >> f[1] >> f[2];
            auto feasible = [&](long double target) {
                long double l = 0, r = 1000;
                for (auto f : v) {
                    long double a = f[0], b = f[1], c = f[2] - target;
                    if (a == 0) {
                        if (b == 0) {
                            if (c > 0)
                                return false;
                        } else if (b > 0)
                            r = min(r, -c / b);
                        else
                            l = max(l, -c / b);
                    } else {
                        long double delta = b * b - 4 * a * c;
                        if (delta < 0)
                            return false;
                        long double sq = sqrtl(delta);
                        l = max(l, (-b - sq) / (2 * a));
                        r = min(r, (-b + sq) / (2 * a));
                    }
                    if (l > r)
                        return false;
                }
                return true;
            };
            long double low = -5005000, high = 100005005000.L;
            for (int it = 0; it < 100; ++it) {
                long double mid = (low + high) / 2;
                if (feasible(mid))
                    high = mid;
                else
                    low = mid;
            }
            if (fabsl(high) < .00005L)
                high = 0;
            if (fabsl(high) < .00005L)
                high = 0;
            cout << high << '\n';
        }
    }
    
    • 1

    信息

    ID
    1735
    时间
    1000ms
    内存
    64MiB
    难度
    普及
    标签
    递交数
    1
    已通过
    1
    上传者