利用根是两位小数且两根之差至少为 1 的约定,在 [-100,100] 上以 0.01 步长从左到右扫描,命中 |f(x)|≤1e-5 的网格点即根,三次命中天然有序。
OJ: roj
题目 ID: 1238
难度:入门
标签:枚举数学python
创建: 2026-09-30 01:09
更新: 2026-10-05 06:24
题目描述
给定实系数
思路
根都是两位小数,因此在
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 01:12
# update_at: 2026-09-30 01:12
import sys
EPS = 1e-5 # 判根阈值:网格点处 |f(x)| ≤ 1e-5 即认为是根(与评测参考实现一致)
def solve() -> None:
a, b, c, d = map(float, sys.stdin.buffer.read().split())
def f(x: float) -> float:
"""方程左端 ax^3+bx^2+cx+d 在 x 处的取值(秦九韶形式)。"""
return ((a * x + b) * x + c) * x + d
roots: list[float] = []
x = -100.0
for _ in range(3): # 依次找最小、次小、最大的根
while x - 100 <= EPS: # 网格从 -100 扫到 100(含端点,与参考实现一致)
if abs(f(x)) <= EPS:
break # 命中一个根:根是两位小数且两两之差 ≥ 1,步长 0.01 必能扫到
x += 0.01
roots.append(x) # 命中的网格点;若数据不满足"三个实根"约定则与参考实现同样扫到界外
x += 0.01 # 跳过当前根所在的网格点,继续找下一个根
print(' '.join(f'{r:.2f}' for r in roots))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 06:19
* update_at: 2026-10-05 06:24
*/
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;
typedef long long ll;
const double EPS = 1e-5; // 判根阈值:|f(x)| ≤ 1e-5 即认为是根
double a, b, c, d; // 一元三次方程 ax^3 + bx^2 + cx + d = 0 的系数
// 秦九韶形式求多项式在 x 处的取值
inline double f(double x) {
return ((a * x + b) * x + c) * x + d;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> a >> b >> c >> d;
double x = -100.0; // 从区间左端点开始,以 0.01 为步长向右扫描
for (ll i = 0; i < 3; ++i) { // 依次找出三个根
while (x - 100.0 <= EPS) {
if (fabs(f(x)) <= EPS) {
break; // 命中一个网格点根
}
x += 0.01;
}
double root = round(x * 100.0) / 100.0; // 把浮点误差拉回两位小数网格点
if (i > 0) {
cout << ' ';
}
cout << fixed << setprecision(2) << root;
x += 0.01; // 跳过当前根所在网格点,继续寻找下一个根
}
cout << '\n';
return 0;
}