Skip to main content

Boredom Problem Solution - Codeforces 445A (Round 260, Div1)

This is a beautiful beginner level dynamic programming problem, and is quite important if you are just beginning to understand recursion.

Problem Statement - 

Alex doesn't like boredom. That's why whenever he gets bored, he comes up with games. One long winter evening he came up with a game and decided to play it.

Given a sequence a consisting of n integers. The player can make several steps. In a single step he can choose an element of the sequence (let's denote it ak) and delete it, at that all elements equal to ak + 1 and ak - 1 also must be deleted from the sequence. That step brings ak points to the player. Alex is a perfectionist, so he decided to get as many points as possible. Help him.

Problem Source - Codeforces 445A

Let's consider a simple case to begin with, if the sequence is 2 2 2. Then, clearly, Alex has only one choice - to pick the number 2. In that case, his score would be 2*3 = 6.

Moving forward, if the sequence was 2 2 3. Then Alex has two choices - to choose 2, or 3. Now, on choosing 2, his score would be 2*2 = 4. But (2 + 1) = 3 would be eliminated from the sequence, so 4 will be his final score. On the other hand, if he chooses 3, his score would be 3*1 = 3, and yet again, (3 - 1) = 2 will be eliminated from the array. Clearly, the maximal score is 4.

As it is clearly visible, it is the frequency of the number appearing, as well as the number itself that is significant. Hence, we initiate an array, count[i], storing the number of times the element i appears in the sequence.

Hence for the above sequence 2 2 3, count[2] = 2, and count[3] = 3.

Finally, to find the optimal score, it would be easy to first break the problem down into smaller problem. In this case, we break the sequence into smaller sequence and find optimal solution for it.

For the sequence of number containing only 0, the answer would be 0. Similarly, if a sequence contains only the number 0 and 1, then the solution would be count[1]*1.

Now we are ready to build the recursive solution for this problem. For a sequence of number containing only the numbers, 0 to n, we can either pick the nth element, or not. Hence,
dp[i] = 
max(
dp[i - 1], // Not picking the ith number, then the number before it can be considered
dp[i - 2] + i*a[i] // Picking the ith number, then the number before it is eliminated, hence the number before that is considered
);

Once we have the recursive solution, it is quite easy to see, that for the complete sequence of numbers, ie, from 0 to 100000, the solution is simply, dp[100000].

Hence the final code for the problem is -

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

long long int a[100007], n;
long long int dp[100007];

int main() {
    memset(a, 0, sizeof(a));
    cin >> n;
    for (int i = 0; i < n; i++) {
        int j;
        cin >> j;
        a[j]++;
    }
    dp[0] = 0;
    dp[1] = a[1]; // a[1]*1 = a[1]
    for (int i = 2; i <= 100000; i++) { // Finding optimal points until the ith number
        dp[i] = max(dp[i - 1], dp[i - 2] + i*a[i]);
    }
    cout << dp[100000];
    return 0;
}

Comments

  1. why the range of a and dp is 100007 here? why it can't be 100000??
    plz answer.
    thanks :)

    ReplyDelete
    Replies
    1. Just some buffer value. You could have it 100000.

      Delete
  2. count[3]=1 is the correct one

    ReplyDelete
  3. This is the bottom up dp solution for the problem . I'm trying to solve it using top-down dp method but i'm getting difficulty in trying to implement this method . Can you please discuss this method

    ReplyDelete
  4. can anyone explain the dp[i-2] inside the max. Like for what reason are we considering that.

    ReplyDelete
    Replies
    1. Because if we take the ith number, we cannot take the (i-1)th number. So dp[i-2] is being considered.

      Delete
  5. 5

    4 2 3 2 5

    my output from code was 13 but it gave me WA and the output was 9
    I couldn't understand why? help plz!!

    ReplyDelete
    Replies
    1. try, entering the input without the extra Line input after the first integer number

      Delete
  6. This comment has been removed by the author.

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete

Post a Comment

Popular posts from this blog

Maximum Increase - 702A - Codeforces Solution

Formal Problem Statement - You are given array consisting of n integers. Your task is to find the maximum length of an increasing subarray of the given array. A subarray is the sequence of consecutive elements of the array. Subarray is called increasing if each element of this subarray strictly greater than previous. Problem Link - Codeforces - 702A This is a simple problem, with an even simpler solution. We simply transverse across the array comparing each element with the one before it, and maintaining two counters, one for the length of current increasing sequence, and other for the length of overall maxima till this point. Even better, we don't need to store the array, we can transverse by just storing the current, and the element before it. So, the memory required is lesser. After an analysis of this algorithm, we can say that it runs in  θ(n) time. #include <iostream> #include <algorithm> using namespace std; int main() { int n, pRead, cRead;

Greedy Ascent Algorithm - Finding Peak in 2D Array

Formal Problem Statement - Find a peak in a 2D array, where a is a 2D-peak iff a ≥ b, a ≥ d, a ≥ c, a ≥ e. If there are more than one peaks, just return one of them. Greedy Ascent Algorithm  works on the principle, that it selects a particular element to start with. Then it begins traversing across the array, by selecting the neighbour with higher value. If there is no neighbour with a higher value than the current element, it just returns the current element. Logically, this algorithm is correct, as it returns the element - which has none of it's neighbours greater than the current element. After a bit of thought, we can come to the conclusion that, in a worst case, the whole array will be transversed. Hence, its time complexity is Θ(mn) . Finally, the code using recursion would be, #include <iostream> using namespace std; int a[100][100], n, m; int recur(int i, int j) { if (i > 0 && a[i - 1][j] > a[i][j]) return recur(i - 1,