实数二分
例题 HDU-2199 Can you solve this equation?
题目链接
https://vjudge.net/problem/HDU-2199
题面
Description
Now,given the equation 8x^4 + 7x^3 + 2x^2 + 3x + 6 == Y,can you find its solution between 0 and 100;
Now please try your lucky.
Input
The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has a real number Y (fabs(Y) <= 1e10);
Output
For each test case, you should just output one real number(accurate up to 4 decimal places),which is the solution of the equation,or “No solution!”,if there is no solution for the equation between 0 and 100.
Sample Input
2
100
-4
Sample Output
1.6152
No solution!
题解
这题就是最简单的实数二分,原方程是单调的,直接二分求解即可,重点是学习一下实数二分的写法,
AC代码
#include <bits/stdc++.h>
#define eps 1e-8//使用eps控制精度,越小循环次数也就越多
using namespace std;
double y;
double calc(double x) {
return 8 * x * x * x * x + 7 * x * x * x + 2 * x * x + 3 * x + 6;
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%lf", &y);
if (y < calc(0) || y > calc(100)) {
printf("No solution!
");
continue;
}
double l = 0, r = 100;
double mid;
while (r - l > eps) {//循环条件注意是r-l>eps
mid = (r + l) / 2;
if (calc(mid) > y) r = mid;//注意这里是直接等于mid
else l = mid;
}
printf("%.4f
", mid);
}
return 0;
}
注意
当精度过高可能进入死循环风险时,可以通过一个变量控制循环次数,比如100次就停止
整数二分
例题 POJ-2785 4 Values whose Sum is 0
题目链接
https://vjudge.net/problem/POJ-2785
题面
Description
The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .
Input
The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 2 28 ) that belong respectively to A, B, C and D .
Output
For each input file, your program has to write the number quadruplets whose sum is zero.
Sample Input
6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45
Sample Output
5
Hint
Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).
题解
简述一下题意,找到有多少对(a,b,c,d)满足a+b+c+d=0。
n为4000,(n^3logn)枚举前三个的和二分最后一个肯定会超时,那就预处理a+b的和,二分c+d的和即可,复杂度(2n^2logn)可以AC,预处理可以直接用一个multiset处理,(upper\_bound-lower\_bound)即为答案要加上的个数,因为如果没有正好相等的数upper_bound返回的地址刚好等于lower_bound
AC代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 4005
using namespace std;
int a[N], b[N], c[N], d[N];
int sum[N * N];
int main() {
int n;
while (scanf("%d", &n) != EOF) {
for (int i = 1; i <= n; i++) {
scanf("%d%d%d%d", &a[i], &b[i], &c[i], &d[i]);
}
int cnt = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
sum[++cnt] = a[i] + b[j];
}
}
sort (sum + 1, sum + cnt + 1);
long long ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
int x = -(c[i] + d[j]);
ans += upper_bound(sum + 1, sum + cnt + 1, x) - lower_bound(sum + 1, sum + cnt + 1, x);
}
}
cout << ans << endl;
}
return 0;
}
二分答案
类型一:最大化最小值
例题 POJ-2456 Aggressive cows
题目链接
https://vjudge.net/problem/POJ-2456
题面
Description
Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000).
His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?
Input
* Line 1: Two space-separated integers: N and C
* Lines 2..N+1: Line i+1 contains an integer stall location, xi
Output
* Line 1: One integer: the largest minimum distance
Sample Input
5 3
1
2
8
4
9
Sample Output
3
Hint
OUTPUT DETAILS:
FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3.
Huge input data,scanf is recommended.
题解
看到最大化最小值或者最小化最大值,基本都是二分答案的思想,即先二分知道了答案,再判断这个答案是否可行,可行就向右(左)二分找新的答案继续判断,这个题也是这样,先对奶牛的位置排序,二分奶牛之间的距离,如果这头奶牛距离上一次安放的奶牛大于二分的距离就放上,看最后是否放够了C个奶牛。
AC代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 100050
using namespace std;
typedef long long ll;
ll a[N];
int n, c;
bool check(ll x) {
ll pos = a[1];
int tmp = c;
tmp--;
for (int i = 2; i <= n; i++) {
if (a[i] >= pos + x) {
pos = a[i];
if (tmp > 0) tmp--;
if (tmp == 0) break;
}
}
return tmp == 0;
}
int main() {
scanf("%d%d", &n, &c);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
sort (a + 1, a + n + 1);
ll l = 0, r = 1000000050;
ll mid;
ll ans = 0;
while (l <= r) {
mid = (l + r) >> 1;
if (check(mid)) {
ans = max(ans, mid);
l = mid + 1;
}
else {
r = mid - 1;
}
}
cout << ans << endl;
return 0;
}
类型二:最小化最大值
思想同最大化最小值
例题 POJ-3104 Drying
此题有一定思维难度,单独写一篇题解,地址https://www.cnblogs.com/artoriax/p/10375508.html
类型三:最大化平均值
这种类型的题目需要转换一下
例题 POJ-3111 K Best
此题有一定思维难度,单独写一篇题解,地址https://www.cnblogs.com/artoriax/p/10375709.html
三分
例题 HDU-2899 Strange fuction
题目链接
https://vjudge.net/problem/HDU-2899
题面
Description
Now, here is a fuction:
F(x) = 6 * x7+8*x6+7x3+5*x2-yx (0 <= x <=100)
Can you find the minimum value when x is between 0 and 100.
Input
The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has only one real numbers Y.(0 < Y <1e10)
Output
Just the minimum value (accurate up to 4 decimal places),when x is between 0 and 100.
Sample Input
2
100
200
Sample Output
-74.4291
-178.8534
题意
函数的一项系数未知,给定这个系数的值,找出函数的极小值点x
题解
三分模版题,每次舍弃离极值点远的部分
AC代码
#include<bits/stdc++.h>
#define eps 1e-8
using namespace std;
double y;
double calc(double x) {
return 6 * pow(x, 7) + 8 * pow(x, 6) + 7 * pow(x, 3) + 5 * x * x - y * x;
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%lf", &y);
double l = 0, r = 100;
double midl, midr;
while (r - l > eps) {
midl = (l + r) / 2;
midr = (midl + r) / 2;
double cmidl = calc(midl);
double cmidr = calc(midr);
if (cmidl < cmidr) {
r = midr;
}
else l = midl;
}
printf("%.4f
", calc(midl));
}
return 0;
}