You are not logged in. Please login at www.codechef.com to post your questions!

×

KTHMAX - Editorial

PROBLEM LINK:

Practice

Contest

Author: Rishabh

Tester: Kevin Charles Atienza

Editorialist: Vaibhav Tulsyan

DIFFICULTY:

Medium

PREREQUISITES:

Stacks, Binary Search

PROBLEM:

For an array of $N$ integers, you are asked to answer $M$ queries. In each query, you are asked the first number in the $p^{th}$ sub-array, after sorting all numbers in each sub-array in descending order and then sorting the sub-arrays in descending order.

QUICK EXPLANATION:

For each $i (1 \le i \le N)$, calculate the number of subarrays for which $a_i$ is the maximum element. Store indexes $j (1 \le j \lt i)$ and $k (i + 1 \le k \le N)$, such that: - $a_j > a_i$ - $a_k > a_i$ - All integers between $i$ and $j$ are smaller than $a_i$. - All integers between $i$ and $k$ and smaller than $a_i$. Number of subarrays for which $a_i$ is max is equal to $(i - j) * (k - i)$. Sort the elements in descending order and maintain a cumulative sum of no. of subarrays uptil the $i^{th}$ index. Use binary search to find the value associated with the $p^{th}$ sub-array.

EXPLANATION:

Subtask 1:

  • Iterate over all possible sub-arrays of length $1, 2, 3, ... , N$.
  • After fixing the end-points, iterate over the array to find the maximum element.
  • Store the maximum element of each subarray in a list $L$.
  • Sort $L$ in descending order.
  • The maximum element of the $p^{th}$ sub-array would be the $p^{th}$ element in this list $L$.

Complexity: $O(N^3 + N^2.log_2(N) + M)$

This naive solution would time out for Subtasks 2 and 3 and would hence fetch only $20$ points.

Subtask 2:

  • Maintain a list $L$ to store the maximum values of all sub-arrays.
  • Iterate over all possible sub-arrays by fixing the end-points of the array, say $X$ and $Y$.
  • Keep a running maximum element present in all sub-arrays whose left boundary is $X$.
  • For each sub-array, store the newly computed maximum in the list $L$.
  • Sort $L$ in descending order.
  • The maximum element of the $p^{th}$ sub-array would be the $p^{th}$ element in this list $L$.

Complexity: $O(N^2 + N^2.log_2(N) + M)$

This solution would give a total of $50$ points.

Subtask 3:

In order to find the number of subarrays whose max is $a_i$, we can make a useful observation. For each $i$, we can determine a left boundary $j$ and a right boundary $k$ such all integers $a_x (j \lt x \lt i)$ and $a_y (i \lt x \lt k)$ are less than or equal to $a_i$. In other words, let $[j+1 .. k-1]$ represent the longest segment in which no element is greater than $a_i$. Then, the no. of sub-arrays in which $a_i$ is maximum is equal to $(i - j) * (k - i)$.

How do we find these boundaries for all $i$ in $O(N)$ or $O(N.log(N))$ time?

We will use a stack to find the boundaries. Let's try to find only the left boundary for each $i$ first. If the current element being processed, say $Z$, is less than or equal to the element at the top of the stack, say $T$, then the left boundary of $Z$ would be the index of $T$. Otherwise, we keep popping elements from the stack until we find a suitable boundary.

Pseudo-code: stack = [-1] left_boundary = [null for i in (1..n)] for i in [1..n]: while (stack is not empty) and (stack.top <= a[i]): stack.pop() left_boundary[i] = stack.top stack.push(i)

Similarly, we can also compute the right boundary for each $i$.

We have computed the boundaries of all $i$ in $O(N)$ time. This was the slowest step in our previous naive solutions. Now, we need to store the no. of subarrays for which each $a_i$ is maximum, and sort this list in descending order of $a_i$.

The next question is: how do we find the maximum element associated with the $p^{th}$ sub-array?

Since $N$ can be $10^5$, the number of subarrays can be of the order $10^10$. A linear search would result in TLE.

If we maintain a cumulative sum of the no. of subarrays processed in this sorted list, we will get a monotonically increasing sequence. We can apply binary search on this sequence to find the required answer.

Pseudo-code: data = [(a[1], count[1]), (a[2], count[2]), ... , (a[k], count[k])] for i in [1..len(data) - 1]: count[i + 1] += count[i] for query in [1..m]: p = input() low = 0, high = n while high - low > 1: mid = (low + high) >> 1 if count[mid] > p: low = mid else: high = mid return a[high]

Complexity: $O(N + log_2(N)$

AUTHOR'S AND TESTER'S SOLUTIONS:

Setter's solution can be found here.

Tester's solution can be found here.

Editorialist's solution can be found here.

asked 13 Mar '17, 20:27

wittyceaser's gravatar image

2★wittyceaser
3.4k194377
accept rate: 16%

edited 10 Aug '18, 15:49

admin's gravatar image

0★admin ♦♦
19.8k350498541

toggle preview
Preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "title")
  • image?![alt text](/path/img.jpg "title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported
  • mathemetical formulas in Latex between $ symbol

Question tags:

×15,682
×82

question asked: 13 Mar '17, 20:27

question was seen: 216 times

last updated: 10 Aug '18, 15:49