0x04 two points
There are two dichotomous ways:
int l = 0, r = n + 1; while(l < r) { mid = l + (r - l) / 2; if(a[mid] >= x) r = mid; else l = mid + 1; } while(l < r) { mid = (l + r + 1) << 1; if(a[mid] <= x) l = mid; else r = mid - 1; }
1. Cyclic condition l < R
It can be guaranteed that the final l == r at this time, the mid must fall on the correct answer
2. Change of l and r
The first is to find the lower_bound(x), the smallest number greater than or equal to X. when a [mid] > = x, the numbers after mid are certainly not satisfied, and mid may be the correct answer, so r = mid; When a [mid] < x, mid must not be the correct answer, so l = mid + 1;
The second is to find the maximum number less than or equal to X. when a [mid] < = x, the numbers before mid are certainly not satisfied, and mid may be the correct answer, so l = mid; When a [mid] > x, mid must not be the correct answer, so r = mid - 1;
3. Change of mid + [0, n+1]
Mid = L + (R - L) / 2 prevents overflow
Mid = (R + l + 1) < 1 makes mid not equal to l, so as to avoid that when r - l = 1, mid is always equal to l, and an endless loop is formed after entering the l = mid statement;
The original interval [1, n] is extended to [0, n+1] to deal with the case of no solution
Summary: specific analysis
1. Select the corresponding left and right half intervals according to the comparison results between a[mid] and the target value
2. According to the target value to be found, judge whether mid + 1 and mid - 1 are not the correct answer, and then select one of the two supporting half schemes: "r = mid, l = mid + 1, mid = L + (R - L) / 2" and "L = mid, r = mid - 1, mid = (L + R + 1) < < 1"
3. The termination condition is l == r, and this position is the final answer.
Dichotomy on real number field
1. Generally, when k decimal places are reserved, take the precision eps = 1e-(k+2)
2. while condition is L + EPS < R
while(l + eps < r) { double mid = (l + r) / 2; if(calc(mid)) l = mid; else r = mid;
3. If it is difficult to determine the accuracy, the fixed number of cycles is used for bisection, and the accuracy is often even higher
For(i, 1, 100) { double mid = (l + r) / 2; if(calc(mid)) l = mid; else r = mid; }
Example aw102 maximum matrix sum of pre example -- POJ1050
int main () { cin >> n; For(i, 1, n) For(j, 1, n) cin >> mat[i][j]; For(i, 1, n) { clr(s); For(j, i, n) { For(k, 1, n) s[k] += mat[j][k]; int num = 0; For(k, 1, n) { num += s[k]; if(num <= 0) num = 0; ans = max(ans, num); } } } cout << ans << endl; return 0; }
Traverse from row i to row j, and save the sum of each column from row i to row j with sum under different i conditions. After saving row j, find the maximum subarray sum once and compare it with ans, so as to change the two-dimensional into one-dimensional, and find the sum of the maximum submatrixes for all matrices in different rows, and finally get the sum of the maximum matrices
Example aw102 best cattle fence
Title Link: 102. Best cattle fence - AcWing question bank
Main idea: find the maximum average of all subsequences with length not less than L (sum of subsequences / length of subsequences)
Train of thought analysis: real number field dichotomy + prefix and
We can calculate the maximum average by subtracting the average from each item of the sequence to find that the sum of subsequences with length ≥ L is non negative. Since the maximum average is required, the larger the sum of non negative subsequences is, the better (because each item of the subsequence can subtract a larger average and still ensure non negative), that is, after subtracting itself from each item of the sequence, Maximum subsequence and nonnegative maximum mean
**Solution steps: 1. First use the real number field to get the average**
double l = 0, r = 1e6; double mid; double eps = 1e-5; //Keep three decimal places while(l + eps < r) //Real number field dichotomy { mid = (l + r) / 2; if(check(mid)) l = mid; else r = mid; }
2. A new sequence is generated by using the average, and the prefix sum is calculated
3. The sum of the largest subsequences of the new sequence is obtained by using the idea of prefix sum, and whether it is ≥ 0 is judged
bool check(double mid) { For(i, 1, n) s[i] = s[i-1] + a[i] - mid; //Step 2 find the prefix and of the new sequence double minn = 1e6; for(int i = 0, j = f; j <= n; j++, i++) //Using the idea of two pointers, first set the position difference of the pointer to L, and then add 1 synchronously every cycle { minn = min(minn, s[i]); //minn must be the minimum prefix sum that all S[j] can subtract, and subtracting the minimum is the sum of the maximum subsequences if(s[j] - minn >= 0) return true; //If the conditions are met, continue dichotomy to find the optimal solution } return false; }
Full Code:
//#pragma comment(linker, "/STACK:10240000000000,10240000000000") //#pragma GCC optimize(2) #include <bits/stdc++.h> #define For(i,a,b) for (int i=(a);i<=(b);++i) #define Fod(i,b,a) for (int i=(b);i>=(a);--i) #define mls multiset #define lb lower_bound #define ub upper_bound #define pb push_back #define pob pop_back #define itt iterator #define clr(x) memset(x, 0, sizeof(x)); typedef long long ll; typedef unsigned long long ull; using namespace std; const int MAXN = 0x7fffffff; int n, f; double a[100005]; double b[100005]; double s[100005]; bool check(double mid) { For(i, 1, n) s[i] = s[i-1] + a[i] - mid; double minn = 1e6; for(int i = 0, j = f; j <= n; j++, i++) { minn = min(minn, s[i]); if(s[j] - minn >= 0) return true; } return false; } int main () { cin >> n >> f; For(i, 1, n) cin >> a[i]; double l = 0, r = 1e6; double mid; double eps = 1e-5; while(l + eps < r) { mid = (l + r) / 2; if(check(mid)) l = mid; else r = mid; } cout << (int)(r*1000) << endl; return 0; }