A. 一元三次方程求解
本题几乎是这次最难的题目
题目描述
一本通P295,第5题 有形如:
a
x
3
+
b
x
2
+
c
x
+
d
=
0
ax ^{3}+bx^{2}+cx+d=0
ax3+bx2+cx+d=0这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值≥1。 要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。
提示:记方程f(x)=0,若存在2个数x1和x2,且x1<x2,f(x1)
×
\times
× f(x2)<0,则在(x1,x2)之间一定有一个根。 输入:a,b,c,d 输出:三个实根(根与根之间留有空格) 【输入输出样例】 输入:1 -5 -4 20 输出:-2.00 2.00 5.00
输入格式
a , b , c , d a,b,c,d a,b,c,d
输出格式
三个实根(根与根之间留有空格)
管他什么样例呢
First
check 函数
double check(double x) {
return a * x * x * x + b * x * x + c * x + d;
}
于是
#include <bits/stdc++.h>
using namespace std;
double a, b, c, d; // 题中a,b,c,d
double check(double x) {
return a * x * x * x + b * x * x + c * x + d;
}
Second
二分(重点,可以是函数,也可以是在main内)
int main() {
scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
for(double i = -100; i < 100; i ++) { //不用"i <= 100",见下。
if(check(i) == 0) {
printf("%.2lf ", i); //小心空格!
continue;
}
if(check(i) * check(i + 1) < 0) {
int l = i, r = i + 1, mid; //根在此范围内
while(r - l > 0.001) {
mid = (l + r) / 2;
if(check(mid) * check(l) > 0) {
l = mid;
}
else r = mid;
}
printf("%.2lf ", i); //小心空格!
}
}
return 0;
}
完整代码
#include <bits/stdc++.h>
using namespace std;
double a, b, c, d; // 题中a,b,c,d
double check(double x) {
return a * x * x * x + b * x * x + c * x + d;
}
int main() {
scanf("%lf %lf %lf %lf", &a, &b, &c, &d);
for(double i = -100; i < 100; i ++) { //不用"i <= 100",见下。
if(check(i) == 0) {
printf("%.2lf ", i); //小心空格!
continue;
}
if(check(i) * check(i + 1) < 0) {
int l = i, r = i + 1, mid; //根在此范围内
while(r - l > 0.001) {
mid = (l + r) / 2;
if(check(mid) * check(l) > 0) {
l = mid;
}
else r = mid;
}
printf("%.2lf ", l); //小心空格!
}
}
return 0;
}
B. 二分法求函数的零点
本题重点 —浮点数的二分
技巧
正常二分
while(l < r) {
int mid = (l + r) / 2;
if(mid > x) r = mid;
else l = mid + 1;
}
浮点二分
while(l - r > 精度) {
double mid = (l + r) / 2;
if(mid > x) r = mid;
else if(mid < x) l = mid;
else printf("%.精度lf", mid);
}
都懂都懂
那就水了 —
代码
#include <bits/stdc++.h>
using namespace std;
double check(double x) {
return x * x * x * x * x - 15 * x * x * x * x + 85 * x * x * x - 225 * x * x + 274 * x - 121;
}
int main() {
double l = 1.5, r = 2.4, mid;
while(1) {
mid = (l + r) / 2;
if(check(mid) > -0.000001 && check(mid) < 0.000001) {
printf("%.6lf", mid);
return 0;
}
else if(check(mid) > 0.000001) {
l = mid;
}
else r = mid;
}
return 0;
}
C. 和为给定数
三种做法
一.暴力枚举
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000005;
int num[MAXN];
int main() {
int n, m;
for(int i = 1; i <= n; i ++) {
scanf("%d", &num[i]);
}
sort(num + 1, num + n + 1);
scanf("%d", &m);
for(int i = 1; i < n; i ++) {
for(int j = i + 1; j <= n; j ++) {
if(num[i] + num[j] == m) {
printf("%d %d", num[i], num[j]);
return 0;
}
}
}
printf("No");
return 0;
}
看不懂的都是SB
时间复杂度 O ( n 2 ) O(n^{2}) O(n2)
二.剪枝优化
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000005;
int num[MAXN];
int main() {
int n, m;
for(int i = 1; i <= n; i ++) {
scanf("%d", &num[i]);
}
sort(num + 1, num + n + 1);
scanf("%d", &m);
for(int i = 1; i < n; i ++) {
if(num[i] > m / 2) break; //简单剪枝,时间复杂度瞬降!
for(int j = i + 1; j <= n; j ++) {
if(num[i] + num[j] == m) {
printf("%d %d", num[i], num[j]);
break;
}
}
}
printf("No");
return 0;
}
因为经过sort(num + 1, num + n + 1)
语句排序后,若num[i] > m / 2
后,num[i + x](x > 0)
必大于num[i]
,所以num[i] + num[i + x]
必大于
m
m
m。
三. 二分
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000005;
int num[MAXN];
int main() {
int n, m;
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
scanf("%d", &num[i]);
}
sort(num + 1, num + n + 1);
scanf("%d", &m);
for(int i = 1; i < n; i ++) {
if(num[i] > m / 2) break;
int l = i + 1, r = n;
while(l <= r) {
int mid = (l + r) / 2;
if(num[i] + num[mid] < m) l = mid + 1;
else if(m == num[mid] + num[i]) {
printf("%d %d", num[i], num[mid]);
return 0;
}
else r = mid - 1;
}
if(num[l] + num[i] == m) {
printf("%d %d", num[i], num[l]);
return 0;
}
}
printf("No");
return 0;
}
在第二重for
循环中使用二分。
总结
题目不难,重要在用二分算法!!!
本蒟蒻第二篇题解,dalao勿喷