Editorial for COCI '21 Contest 3 #3 Akcija
Submitting an official solution before solving the problem yourself is a bannable offence.
The subsets from the problem have a very rich structure and it is possible to arrive at the solution from different angles. The scoring was generous, but the last subtask should be challenging. For most contestants, the most natural idea was some sort of dynamic programming, but we will present a solution which uses a different (perhaps more complex) idea, which can be generalized to other problems that ask for the
The presented solution consists of several parts:
- How to check if a subset is obtainable?
- How to find the best obtainable subset?
- How to find candidates for the next best obtainable subset?
- How to choose between the candidates to arrive at the
best ones?
The proofs are left as an exercise for the reader.
How to check if a subset is obtainable?
Claim 1: If a subset is obtainable, a valid sequence of calls can be made by ordering the products by
Claim 2: In an empty array put
We can build a min. segment tree over the array from claim 2, which allows us to insert/erase products while maintaining the information whether the current set is obtainable. An update is simply
How to find the best obtainable subset?
The following greedy algorithm works:
Sort the set in question so that
We iterate over the products in order and try to add the current product if it maintains the attainability property (which we can check with the segment tree).
Claim 3: The greedy algorithm produces a set which is maximum in size, and out of all such sets it has the minimum cost, i.e. it is the best choice.
Proof outline: The greedy algorithm produces an obtainable subset which can't be enlarged (i.e. is maximal). Every two maximal subsets are actually of the same size - the maximum one. The order
How to find candidates for the next best obtainable subset?
Let
Claim 4: The best obtainable subset of
We can find the desired
In the segment tree, we store the array from claim 2 for set
How to choose between the candidates to arrive at the
In a given moment, the current search spaces will be described by describing the status of each index:
- This index must be in the set.
- This index can't be in the set.
- For this index, we have a choice whether it is in the set or not.
We'll have a priority queue to store all the different search spaces not yet explored. The search spaces will be disjoint and their union will cover all possibilities not yet visited. In the priority queue, they will be sorted by the cost of the best obtainable subset within that search space.
It was already mentioned how to find the best obtainable subset within a search space. The situation is a bit different since this time we have indices which must/can't be taken. But the idea can easily be modified just by not even taking into consideration the indices which we can't take, and the ones we must take we use for updating the segment tree before executing the greedy algorithm. It's easy to see that the mentioned claims are still true in this modified case.
We pop the minimum element from the priority queue to determine the next best obtainable subset. The popped search space then needs to be partitioned into smaller pieces which don't include the best obtainable subset. Let
- The first element from
can't be taken, for the rest we can choose. - The first element from
must be taken, the second must not, for the rest we can choose. - The first two elements from
must be taken, the third must not, for the rest we can choose. - …
Of course, the indices outside of
We'll have a total of
The presented idea is called fracturing search. The reason a lot of things are true for these obtainable subsets is because they have a matroid structure.
Comments