Editorial for CCC '22 S4 - Good Triplets
Submitting an official solution before solving the problem yourself is a bannable offence.
Author:
For the first subtask, it suffices to follow the definition of a good triplet. Firstly, there are ways to select . Secondly, consider the condition that the origin is strictly inside the triangle. This is equivalent to saying that , , and divide the circle into arcs, and each arc is strictly shorter than . This leads to the following approach. Sort the positions so that , then check that
For example, the first of these checks can be implemented in code as P[b]-P[a] < (C+1)/2
in C++ or
Java, or P[b]-P[a] < (C+1)//2
in Python 3.
For the second subtask, the goal is to find a solution that works well when is small. Let be the number of points drawn at location . If three locations satisfy the second condition, we want to add to the answer. This approach is and is too slow. However, we can improve from three nested loops to two nested loops. If and are chosen already, either does not exist, or is in an interval. It is possible to replace the third loop with a prefix sum array. This algorithm's time complexity is .
It is possible to optimize this approach to and earn marks. The idea is to eliminate both the and loop. Start at and compute in time. The next step is to transition from to , and to maintain in time. This requires strong familiarity with prefix sum arrays. Care with overflow and off-by-one errors is required.
Comments
I found this problem a lot easier to think about if you count triplets of points that don't form a triangle and subtract that from the total number of triplets. These are exactly the triplets whose points all belong on a closed half of the circle, so sweeping two pointers along the circle suffices to do this in time.