Basic algorithm -- binary search and binary answer analysis

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;
}		

Posted by milesap on Thu, 04 Nov 2021 13:20:24 -0700