WEIRD2 - EDITORIAL

PROBLEM LINK:

Practice
Contest: Division 1
Contest: Division 2

Setter: Hasan Jaddouh
Tester: Teja Vardhan Reddy
Editorialist: Taranpreet Singh

DIFFICULTY:

Easy-Medium

PREREQUISITES:

Observation, Amortized analysis and data structures.

PROBLEM:

Given an array A of length N, find out the number of ordered pairs (a,b) such that a appears at least b times in array while b appears at least a times in the array.

QUICK EXPLANATION

  • Sort the given array, and for every position, iterate over the positions having less than the frequency of current element.
  • Above solution works in overall O(N) time because, at every iteration, we iterate over at most F[i] elements in each iteration where F[i] is the frequency of A[i]. Since \sum F[i] = N, Overall complexity is O(N).

EXPLANATION

For this problem, I have two solutions to offer, First the intended solution, which is used by Setter and Tester, while the other one is my solution.

Let us make input in form of frequency mapping tuples (A[i],F[i]), where F[i] denote frequency of A[i] in input array.

Bruteforce Solution: Iterate over every ordered pair (i,j), i \leq j of values and check if F[j] \geq A[i] and F[i] \geq A[j] holds.

Since we iterate over all pairs of values, this solution has complexity O(N^2).

Now, let us rewrite the conditions of a valid pair. For pair (A[i], A[j]) to be valid, we need F[j] \geq A[i] and F[i] \geq A[j].

Let us sort these tuples in increasing order of A[i] and run the same loops as BruteForce. Now, notice, that for any (A[i], F[i]), if we get the position A[j] > F[i] for any position j, we can safely see, that No position k, k > j will satisfy F[i] \geq A[k]. Hence, we can break out from internal loop as soon as we reach a value A[j] > F[i].

Now, What is the time complexity of this solution? This is where Amortized Analysis comes into play.

See, For every position, we iterate over at max F[i] element in inner loop. Since N = \sum F[i], The overall solution complexity is bounded by N, resulting in overall O(N*logN) solution due to sorting.

Now, Let’s discuss Editorialist solution in brief, who didn’t get the observation at first.

Make frequency tuples same way as above solution and sort tuples by non-decreasing order of F[i]. If we focus on condition A[i] \leq F[j], we know that this condition will hold for a suffix of the array due to the non-decreasing order of F. This way, Now we need to count the number of positions in Suffix [j, N-1] for which A[j] \leq F[i]. Let’s call (j, F[i]) a query, and j is the left end of query range, right end being the end of the array.

There exist a more general problem which can be applied here. Given an array of length N, Perform two type of operations. First is to update a single element. Other is to count number of elements \leq x in range [l, r].

Editorialist just uses Order statistic tree, along with sorting queries (j, F[i]) by decreasing order of j, and answer queries and add elements to order statistic tree as the j decreases, and making queries when the current range of added elements correspond to query range.

The time complexity of this solution too is O(N*logN) but is probably slower than the first solution due to the constant factor.

This was a lesson, that observations matter. :stuck_out_tongue:

Related problem

The problem Tufurama seems a lot similar to this problem, though have quite a different solution which is worth a try.

Also, The problems KQUERY and KQUERY2 are nice problems to practice if you tried the second solution.

Time Complexity

The time complexity of both solutions is O(N*logN) but the first one has lower constant factor than the second solution.

AUTHOR’S AND TESTER’S SOLUTIONS:

Setter’s solution
Tester’s solution
Editorialist’s solution

Feel free to Share your approach, If it differs. Suggestions are always welcomed. :slight_smile:

2 Likes

Yeah, I tried using the tufurama approach, but the complexity was too much. Is there a different way of applying mergesort tree to solve this problem?

Well, we need to answer queries of type KQUERY, whichever method you may apply.

HERE is my solution.
which is O(n+10^6)
Seems to be same as setter… but this is not O(n*log(n))
Still confused about time complexity… can anyone help ?

reader functions and huge templates and assert statements annoys a lot in checking solutions :frowning:

OMG I also used the setters approach without knowing! Its a lot of fun when you realize you did it in setters method :). Thank you for editorial taran!

I agree. So many random defines hinder readibility >_<

1 Like

@l_returns hacked your soln. Check Hacked Soln.

TC is hard coded instead of reading. Takes 1.5 sec and TL is 1 sec.

this is my code that pass all test cases.however when i use unordered_map it gives wrong answer.suggest some
test case where it fails.

link to my solution:
https://www.codechef.com/viewsolution/21247254

1 Like

Your complexity is omega(T*1e6) but inner loop is not executed many times so it passed.

1 Like

Such a difference doesnt really matter @aryanc403 …XD

1 Like

I failed to understand setter soln. So link of your well-commented soln, please. xD

Her (or his…?) profile doesnt show any submission XD

This reminds me of that moment … :stuck_out_tongue:

In the ordered map, all tuples are ordered by key, while in unordered, they can appear in any order, making your solution incorrect, when an unordered map is used.

As usual. I know this profile just logs in to post such comments at my editorials.

Just stop it!!

Setter seems to be having same solution @aryanc403 XD…

See editorialist’s solution, if looking for anything different xD

Lol @l_returns.

@aryanc403 -yup…I recall that too :stuck_out_tongue:

lol. Plagiarism Detected. In coming days we will see a drop admin’s rating.

//