Rating changes for last rounds are temporarily rolled back. They will be returned soon. ×

Problem 466C
Difference between en6 and en7, changed 259 character(s)
An explanation for my solution to [problem:466C]. Credit goes to [Coding Hangover](https://codinghangover.wordpress.com/2015/03/08/codeforces-266-div-2-number-of-ways/) for the algorithm. This post will detail the approach outlined there, explained with an example.↵

#### Problem Statement↵
Given an array `arr`, compute the number of ways we can partition `arr` into three chunks such that the elements in each chunk sum to the same number. For example, the answer for `arr = [1 2 3 0 3]` is `2` because we can have the following splits:↵

- `[1 2]` `[3]` `[0 3]`↵
- `[1 2]` `[3 0]` `[3]`↵

We will use `arr` as our running example throughout.↵

#### Naive Approach↵
First, define `S = sum(arr)`. Verify `S % 3 == 0`. If this is false, then it is impossible to partition `arr` into three equally sized chunks and the answer is `0`.↵

Else, we continue. Pre-compute array `A` which is a running sum of `arr`:↵

~~~~~↵
A = [1 3 6 6 9]↵
~~~~~↵

Iterate `i = 0...n-2` through `A` until we hit `A[i] == S/3`. At this point, we have a potential first chunk. We then iterate `j = i+1...n-1` through `A[i+1:]` until we hit `A[j] == (2/3)S`. This corresponds to a potential middle chunk whose sum is `S/3`. Note that as long as `j < n-1`, it is guaranteed that `sum(arr[j+1:]) = S/3` because we verified that `sum(arr) % 3 == 0` up front. Hence this is a valid partitioning of `arr`. Repeat this process for each potential first and second chunks.↵

Unfortunately the runtime for this approach is `O(n^2)` given the doubly-nested for-loop. Given that `n = 5*10^5` in the worst case, in the worst case we will perform `(5*10^5)^2 = 25*10^10` operations, which will take approximately 250 seconds. Clearly this is too long. Given the maximum value of `n`, we need to cut down the runtime to `O(n*logn)` at worst.↵

#### A Better Algorithm↵
It may be surprising that there is actually a `O(n)` solution. The intuition is that we will still iterate `i = 0...n-2` through `A` identifying potential first chunks. But instead of having to iterate linearly through `A[i+1:]` to compute the number of ways `A[i+1:]` can be split up into `2` chunks each having `S/3` elements, we will pre-compute another array which will allow us to compute this value in constant time.↵

To this end, we pre-compute an array `is_suffix` where `is_suffix[i] = 1` if `sum([i:]) == S/3` and `0` otherwise:↵

~~~~~↵
is_suffix = [0 0 0 1 1]↵
~~~~~↵

Then we compute another array `nb_suffix` where `nb_suffix[i] = sum(is_suffix[i:])`. In words, `nb_suffix[i]` is the number of suffixes contained in `arr[i:]` that sum to `S/3`:↵

~~~~~↵
nb_suffix = [2 2 2 2 1]↵
~~~~~↵

Now we have everything we need. We iterate `i = 0...n-2` through `A` until we hit a potential first chunk. Then the number of ways to split up `arr[i+1:]` into `2` chunks whose elements each sum to `S/3` is simply `nb_suffix[i+2]`. Why `i+2`? Because we need a first, second, and third chunk. `nb_suffix[i+2]` gives us the number of valid last chunks. For each of these last chunks (say it starts at index `k`), the corresponding middle chunk (which starts at `j = i+1` and ends at `j = k-1`) is guaranteed to sum to `S/3` because the first and last chunks sum to `(2/3)*S` and we verified up front that `S % 3 == 0`.


For more intuition for the `i+2` quantity, consider the case where `nb_suffix[i+1] == 1` and `is_suffix[i+1] == 1`. If we used `i+1` instead of `i+2`, then we would erroneously count this instance as a 3-patition even though the middle partition is empty.

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en7 English ebanner 2016-10-29 21:29:39 259 (published)
en6 English ebanner 2016-10-29 21:27:49 527 Tiny change: 'nk sum up up to the' -
en5 English ebanner 2016-10-29 21:06:10 3732
en4 English ebanner 2016-10-29 20:40:43 1001 Tiny change: 'explained along with an e' -
en3 English ebanner 2016-10-29 20:15:37 1803
en2 English ebanner 2016-10-29 19:55:58 884
en1 English ebanner 2016-10-29 19:46:02 658 Initial revision (saved to drafts)