Blue Bridge Cup Selected Question Series - Interval Maximum - Multiplication Method

Today, we will talk about the third algorithm, which has been included in this column . Without further ado, let’s get to the point.
Multiplication and dichotomy are "opposite" algorithms. Bisection is doubling each time, thereby narrowing down to the solution extremely quickly in O(logn) steps; doubling is doubling each time, thereby expanding extremely quickly to a maximum of 7 in O(2 n ) steps space. So both doubling and bisection are very efficient.
Application scenarios of dichotomy and doubling The
dichotomy is to narrow the interval, and finally locate a very small interval, so small that the left and right endpoints of this interval coincide (or almost coincide), so as to obtain a solution, and the solution is the value of the last very small interval. Therefore, the applicable occasion of the dichotomy method is to narrow the query range by bisection on an ordered sequence or an ordered curve, and its purpose is to find a specific value.
Multiplication, on the contrary, is to expand from a small interval to a large interval. In interval problems, it is to solve problems related to interval queries on large intervals, such as interval maximum or minimum. Such applications , such as the RMQ problem mentioned in this lecture , are solved by the multiplication-based ST algorithm.
In addition to its application to intervals, multiplication can also be used for precise numerical calculations. If the elements in the space satisfy the multiplication relationship, or can use the multiplication relationship to calculate, then the multiplication method can also be used to achieve the purpose of solving the exact value of these elements.
Next, let's talk about a classic application of multiplication - the ST algorithm.

ST (Sparse Table) algorithm

The ST algorithm is an excellent algorithm for solving RMQ problems, and it is suitable for RMQ queries in static spaces.

RMQ problem in static space (Range Minimum/Maximum Query, interval maximum value problem): Given a static sequence of length n, do m queries, each time given L, R≤n, within the query interval [L, R] the maximum value. Take the interval minimum problem as an example.

Use brute force to search for the minimum value of the interval [L, R], that is, compare each number in the interval one by one, the complexity is O(n); m queries, the complexity is O(mn). Violent laws are inefficient. What about the ST algorithm?

The ST algorithm is derived from such a principle: if a large interval can be covered by two small intervals, then the maximum value of the large interval is equal to the maximum value of the two small intervals. For example, in the figure below, the large interval {4, 7, 9, 6, 3, 6, 4, 8, 7, 5} is divided by two small intervals {4, 7, 9, 6, 3, 6, 4, 8} , {4, 8, 7, 5} cover, the minimum value of the large interval is 3, which is equal to the minimum value of the two small intervals, min(3,4)=3. In this example, there is a partial overlap between the two cells, and the overlap does not affect the result.
Figure 1 The large interval is covered by two small intervals
Figure 1 The large interval is covered by two small intervals

The basic idea of ​​the ST algorithm is obtained from the above principles, including two steps:

  1. Divide the entire sequence into many sub-intervals, and calculate the maximum value of each sub-interval in advance;
  2. Query the maximum value of any interval, find the two sub-intervals covering it, and use the maximum value of the two sub-intervals to calculate the answer.

So how to design an efficient algorithm for these two steps?
1. Divide the sequence into sub-intervals by multiplying.
For each element of the sequence, divide the sequence from it into sub-intervals of length 1, 2, 4, 8, …. The figure below shows an example of a partition, which is divided into many groups by the length of the cell interval.

Group 1 is a cell of length 1, with n cells, each with 1 element;
Group 2 is a cell of length 2, with n cells, each with 2 elements;
the third group is a small interval of length 4, there are n small intervals, and each small interval has 4 elements;
...... A total of logn groups.
Please add image description
Figure 2 is divided into small intervals by doubling
We can find that the maximum value of the small interval of each group can be recursively derived from the previous group. For example, the maximum value of the third group {4, 7, 9, 6} can be obtained recursively from the maximum value of the second group {4,7}, {9,6}.
So we define dp[s][k], which means that the left endpoint is s, and the interval length is 2 k . Note: 1<<(k-1) is equal to 2^{k-1} Example: 2<<3 = 2 * 2 3
The recurrence relation is: (remember)
dp[s][k]=mindp[s] [k−1],dp[s+1<<(k−1)][k−1]
2. Query the minimum value of any interval To query the minimum value of
an arbitrary interval [L, R], it is to find the value with L as The interval of the starting point (the endpoint of the interval is less than R), and the interval with the endpoint of R (the starting point is greater than L), the intersection of these intervals is [L, R]. The above partitioning method has the following conclusions: starting with any element, there are cells with lengths 1, 2, 4, ...; with any element as the end point, there are also cells with lengths 1, 2, 4, ... in front of it. According to this conclusion, the interval [L, R] to be queried can be divided into 2 sub-intervals, and these two sub-intervals belong to the same group: the inter-unit with L as the starting point and the inter-unit with R as the end point, Let these two small intervals cover [L, R] end to end, and the maximum value of the interval is obtained from the maximum value of the two small intervals. The computational complexity of a query is O(1).
So how do I determine the length of these two small intervals?
First, the length of the interval [L,R] is len = R - L+1. Assume that the lengths of the two small intervals are both x, where x is the largest multiple of 2 smaller than len, and there are x≤len and 2×x≥len, so as to ensure coverage. In addition, dp[][] needs to be calculated. According to the definition of dp[s][k], there are 2 k =x. For example, len=19, x= 16, 2 k =16, k=4.
So how do you find k when len is known? The calculation formula is k=log2(len)=log(len)/log(2), rounded down. Both of the following codes are OK:
base 10 library function log(): int k=(int)(log(double(R-L+1)) / log(2.0));
base 2 library function log2(): int k=log2(R-L+1);
Finally, the calculation formula for the minimum value of the interval [L, R] is given, which is equal to the minimum value of the two small intervals covering it: min(dp[L][ k],dp[R−(1<<k)+1][k]);

Well, let's make a question to see the specific application of the multiplication method. It is best to remember the code template of the multiplication method.

Topic description

Given an array a of length N whose values ​​are a1,a2,…,aN respectively.

There are Q queries, each query contains an interval, please answer the maximum value of the interval.

enter description

The first line of input contains two positive integers N, Q, which represent the length of the array a and the number of queries, respectively.

Line 2 contains N non-negative integers a1,a2,…,aN representing the values ​​of the elements of array a.

Lines 3∼Q+2 represent a query, each query contains two integers L, R, representing the left and right endpoints of the interval

1≤N,Q≤5×105,1≤l≤r≤N,-109≤k,ai ≤109

output description

The output consists of Q lines, each line containing an integer representing the answer to the corresponding query.

sample input

5 5
1 2 3 4 5
1 1 
1 2 
1 3
3 4
2 5

Sample output

1
2
3
4
5

detailed answer

from math import *

maxn = 100001   
dp_max = [[0 for col in range(40)] for row in range(maxn)] #定义一个二维数组,初始化

def st_init():
    global dp_max
    for i in range(1,n+1): dp_max[i][0] = a[i]
    p = int(log2(n))
    for k in range(1, p+1):
        for s in range(1, n+2-(1<<k)):
            dp_max[s][k]=max(dp_max[s][k-1], dp_max[s+(1<<(k-1))][k-1])

def st_query(L,R):
    k = int(log2(R-L+1))
    return max(dp_max[L][k],dp_max[R-(1<<k)+1][k])

n,m =  map(int, input().split())
b = list(map(int,input().split()))
a = [0]*maxn
for i in range (1,n+1): a[i]=b[i-1]   #从a[1]开始。不用a[0]
st_init()
for i in range(1,m+1):
    L,R = map(int, input().split())
    print(st_query(L,R))

Guess you like

Origin blog.csdn.net/m0_51951121/article/details/122676209