CHEFAOR - Editorial



Author: Roman Furko
Testers: Pushkar Mishra and Sergey Kulik
Editorialist: Pawel Kacprzak and Pushkar Mishra
Russian Translator: Sergey Kulik
Mandarian Translator: Gedi Zheng




DP, Bitwise Operations


Given an array A of N integers ranging from 0 to 2^{30}, partition this array into K consecutive sub-arrays such that the sum of Bitwise ORs of these sub-arrays is maximized.

Naive Approach

The simplest approach is to try out all possible partitions using recursion and take the maximum. This approach will try out at least {N \choose K-1} possibilities. It is clearly inefficient and will time-out for all sub-tasks.

An \mathcal{O}(N^2K) solution:

We can use Dynamic Programming. Let us maintain a 2-D array DP[][] in which DP[i][j] stores the maximum sum that you can get by partitioning the segment 1 \dots i into j sub-segments. Evidently, this is an optimal overlapping sub-structure of the main problem.

To calculate DP[i][j], we can iterate from p = i-1 \dots 1 and use the relation:

DP[i][j] = max(DP[i][j], DP[p][j-1] + BitwiseOR(A[p+1], A[p+2], \dots, A[i])).

Since N, K \geq 1000, this algorithm will time out for the last two sub-tasks.

Optimising the DP to \mathcal{O}(NK\log(A_{max})) :

We make two observations:

  • DP[p][j] \leq DP[i][j] for p \leq i. This isn’t difficult to infer since Bitwise OR operation on two numbers never results in a number smaller than either of the two.
  • Let us consider an array C where C[i] = BitwiseOR(A[1], A[2], \dots, A[i]). For i > 30, we claim that there are only 30 distinct values in the array C. The reason is that cumulative Bitwise OR operation accumulates ‘1’ bits. Since the maximum number of ‘1’ bits in the values stored in array C can be 30, thus there can only be 30 distinct values in array C.

Now, using the two aforementioned observations, we can optimize our DP. While calculating DP[i][1 \dots K], we were iterating from p = 1 \dots i-1 and checking DP[p][1 \dots K]. But we can now say that we only need to iterate from 1 \dots K for those p where BitwiseOR(A[p], A[p+1], \dots, A[i]) and BitwiseOR(A[p+1], A[p+2], \dots, A[i]) are different. Since, there can at max be 30 such p, therefore, the net complexity comes down to \mathcal{O}(NK\log(A_{max})). This will easily finish in under 10 seconds.

An \mathcal{O}(NK) solution :

The \mathcal{O}(N^2K) DP solution can directly be optimised to \mathcal{O}(NK) DP using a widely known optimisation method called “Knuth Optimisation”. Though this was not required to solve the problem for 100 points, we suggest that you go through the concept:



1 Like

Can someone tell me why my O(NKlog(A)) solution gives TLE?



Show us some solution please!

Why would you ever swap the order of [Author,Tester] => [Tester,Author]?

Can someone tell me why my O(NKlog(A)) solution gives TLE?


Can someone tell what is the complexity of my code , I feel it is the same as required and gives TLE.

Nice joke about “easily finish under 10 seconds”.

Here’s author’s code from editorial, submitted in practice: link

1 Like

can someone tell me if the Tester2 is based on knuth optimization?

Try to solve it using a Divide and Conquer approach, this is another kind of dynamic programming optimization that runs in O(KNlogN), and here’s my solution that runs in 6.90 s

PD: You can read about it here

I coded the solution after going through editorial(but it is top-down approach).I could pass first sub-task only.Can someone figure out what optimization i have to do to my code to pass other sub-tasks.I think I have taken care of trick mention in editorial.Plz help !!

added tester’s and author’s solutions

same here.

Got it , precedence can make you cry! :smiley: . Morover use memset over simple loop to fasten up your code!!

Bad constant?

Hm… that’s sad actually if you get the correct, but can not implement it properly. Where could I improve?

Try to submit NKlog(A) code from editorial, you’ll be surprised :slight_smile:

What exactly is the problem with the NKlogA solution from the editorial?

On the testing server, all test files were passing under 8 seconds. Author’s solution was only for first 2 subtasks. it was wrongly uploaded here. the correct solutions are up now. Try submitting tester2’s solution.

Tried tester1, it works 8.3 on maxtest. Far from TL*0.5 :slight_smile: I agree that getting TL because of bad implementation why AC is possible is a contestant’s fault, but that’s definitely not “easily finish” :slight_smile: Looking at other comments in this topic - I am not the only one who thinks this way.

And what was the point about “try tester2’s”? It is complitely different solution, based on Knuth optimization; it has nothing to do with NKlogA.

Hello, sorry for reviving this old thread. I was trying this question using divide and conquer optimization but it fails one test case in the largest and I am confused on how to try to further optimize it… My code is pretty straight forward and clean, please have a look at it. Is there something I can try to optimize my code. Or should I go with Knuth optimization as mentioned?

Link to code

Thank you