Problem Link
Difficulty
Medium-Hard
Pre-requisites
Treap, bitset, DP
Problem
Maintain two types of modifications on the given array and solve the subset-sum problem on its’ subsegments.
How to get 25 points
For the beginning, let’s focus on the solution to the first subtasks. The constraints are rather small, so all the modifications can be done naively, in the straightformard way. Namely, if you need to change the value of an element, you can do this in O(1) time, and when you need to reverse the subarray, straightforward O(N)-per-reverse approch will do.
Let’s deal with the queries of the third kind.
The following simple DP technique will help us to determine - whether it is possible to get W as the sum of some of these numbers or not. First of all, pseudocode:
fill dp[] with zeroes
dp[0] = 1
for i = L; i <= R; ++i
for j = W; j >= a[i]; --j
dp[j] |= dp[j - a[i]]
Now, let’s have a closer look to the provided code. Suppose that we operate on the array a[]. The value of dp[k] will be equal to one if it is possible to collect the sum of k from the given integers and will be equal to zero otherwise. Initially, only dp[0] is non-zero.
Then, step by step we recalculate the values of dp[] by adding the integers from the given set one-by-one. The value of dp[j] will become equal to one during the adding of the ith element (say a[i]) if it was possible to collect a sum of (j - a[i]) before. Of course, we consider that j ≥ a[i].
The whole complexity of the described solution is O(NQ+PNW) or simply O(N(Q+PW)).
This solution will be sufficient to solve the first and the second subtasks.
How to get 50 points
At this point, we won’t speed the modifications up, but will improve the execution time of the subset-sum part.
For doing this, we will have two crucial optimizations.
The first optimization
Now it’s time to remember that there are only K ≥ 10 types of the element of the array a[] (aka weight-plates). During each of the subset-sum queries we process R-L+1 elements of a[] which can be optimized to O(K log (N / K)) = O(K log N) - considering the small value of K it will be good.
Let’s calculate the number of weight plates of each kind. Now, consider a single kind of weight plates and suppose that there are X plates of this kind. Let’s create the new summands for our subset-sum problem by grouping the weight plates:
- The first summand should be equal to the weight of one weight plate;
- The second summand should be equal to the weight of two weight plates;
- The third summand should be equal to the weight of four weight plates;
- And so on: the ith summand should be equal to the weight of 2(i-1) weight plates;
At some moment, you won’t be able to create one more summand. This moment is when the amount of the weight plates you need for the new group is greater than the amount of the weight plates that are left. In this case, the last group should contain all the remaining weight plates.
Now, let’s consider some examples of making the groups for the different amount of weight plates:
- If you have 1 weight plate, there will be a single group containing this weight plate;
- If you have 2 weight plates, there will be two groups, each containing a single weight plate;
- If you have 3 weight plates, there will be two groups - the first containing a single weight plate and the second containing two weight plates;
- If you have 4 weight plates, there will be three groups - the first containing a single weight plate, the second containing two weight plates and the third, again, containing a single weight plate.
- Finally, if you have 100 weight plates, there will be 7 groups, containing 1, 2, 4, 8, 16, 32 and 37 weight plates respectively.
This way, for each kind of the weight plates, you will have no more than O(log N) summands that results in O(NQ + PWK log N) complexity.
The second optimization
Consider the version of the subset-sum DP that was shown in “How to get 25 points” part. You can note that all the elements of dp[] are either ones or zeroes and the operations on them are binary - to be more precise, only binary OR.
This enables us to use bitset, so we can speed the code up in 32 times.
Now we’ve got O(NQ + PWK log N / 32) solution that can additionally solve the third subtask. Such solution gets 50 points.
Getting full points
We’ve already achieved O(NQ + PWK log N / 32) complexity. Let’s note that for the constraints of the problem the O(PWK log N / 32) part is already small enough. That means that now we process the queries of the third kind fast enough. Now we need to improve the processing of the queries of the first and the second kind.
Both these queries are actually correspond to a very standard problem - maintain the array under the following queries:
- Reverse a subarray of the array in O(log N) time;
- Change the value of a single array’s element in O(log N) time;
This problem is easily solvable with a data structure called treap.
In our problem, there is one more query that should be maintained:
- Find the amount of the weight plates of each kind on a given segment
For doing this, we can simply store an array of K elements in each node of the treap, where the ith element of this array will denote the number of the weight plated of the ith kind on the corresponding segments. That gives us O(K log N)-per-modification time for the modification query of the both - the first and the second kinds.
Eventually, we get the complexity of O(QK log N + PWK log N / 32). This solution passes all the subtasks and gets 100 points.
Setter’s Solution
Can be found here
Tester’s Solution
Can be found here