Given an array arr[] of size N (1 <= N <= 100), which consists of positive numbers representing different items, two items in the array will be treated as identical if arr[i] == arr[j]. In each round, you can select k consecutive identical items, then remove all identical items, and gain k*k points. The task is to determine the maximum number of points that can be obtained by making the array empty.
Examples:
Input: arr = {1,3,2,2,2,3,4,3,1}
Output: 23
Explanation: {1, 3, 2, 2, 2, 3, 4, 3, 1}
{1, 3, 3, 4, 3, 1} (3*3=9 points)
{1, 3, 3, 3, 1} (1*1=1 points)
{1, 1] (3*3=9 points)
{} (2*2=4 points)Input: arr = {1,1,1}
Output: 9Input: arr = {2}
Output: 1
Approach: To solve the problem follow the below steps:
- Let dp(l, r, k) represent the maximum points we can obtain from a sequence of items within the range [l, r] if we have an additional k items of the same type as the item at position l on the left side.
- For example: if we have a sequence of items {3, 3, 1, 3, 3}, then dp(l=3, r=4, k=2) is the maximum points we can obtain from the subsequence {3, 3} if we have an extra 2 items of the same type as the item at position 3 on the left side, effectively making it {3, 3, 3, 3}.
- Now, let’s consider our options:
- Option 1 is to remove all items with the same type as arr[l]. The total points we can get in this case are dp(l+1, r, 0) + (k+1)*(k+1) (k left items and the lth item have the same type).
- Other option,is that we try to merge non-contiguous items of the same type together, by:
- Finding the index j, where l+1 <= j <= r such that arr[j] == arr[l].
- The total points we can get in this case are dp(j, r, k+1) + dp(l+1, j-1, 0).
- Choose the option with the maximum score to maximize the points.
Illustration of Options:
Below is the implementation of the above idea:
// C++ code for the above approach: #include <iostream> #include <vector> using namespace std;
// Memoization table to store computed results int memo[200][200][200] = {};
int dp(vector< int >& arr, int l, int r, int k)
{ // Base case: no elements left
if (l > r)
return 0;
// Return memoized result, if available.
if (memo[l][r][k] > 0)
return memo[l][r][k];
int lOrginal = l, kOrginal = k;
while (l + 1 <= r && arr[l] == arr[l + 1]) {
// Increase both `l` and `k` if they have
// consecutive identical items with `arr[l]`
l += 1;
k += 1;
}
// Option 1: Remove all elements which
// have the same item as `arr[l]`
int ans = (k + 1) * (k + 1) + dp(arr, l + 1, r, 0);
// Try to merge non-contiguous items of
// the same type together,
for ( int m = l + 1; m <= r; ++m) {
if (arr[m] == arr[l])
ans = max(ans, dp(arr, m, r, k + 1)
+ dp(arr, l + 1, m - 1, 0));
}
// Memoize the result and return it
return memo[lOrginal][r][kOrginal] = ans;
} // Driver code int main()
{ vector< int > arr = { 1, 3, 2, 2, 2, 3, 4, 3, 1 };
int maxPoints = dp(arr, 0, arr.size() - 1, 0);
// Function Call
cout << "Maximum points: " << maxPoints << endl;
return 0;
} |
import java.util.Arrays;
public class MaximumPoints {
// Memoization table to store computed results
static int [][][] memo = new int [ 200 ][ 200 ][ 200 ];
public static int dp( int [] arr, int l, int r, int k)
{
// Base case: no elements left
if (l > r)
return 0 ;
// Return memoized result, if available.
if (memo[l][r][k] > 0 )
return memo[l][r][k];
int lOriginal = l, kOriginal = k;
while (l + 1 <= r && arr[l] == arr[l + 1 ]) {
// Increase both `l` and `k` if they have
// consecutive identical items with `arr[l]`
l += 1 ;
k += 1 ;
}
// Option 1: Remove all elements which have the same
// item as `arr[l]`
int ans = (k + 1 ) * (k + 1 ) + dp(arr, l + 1 , r, 0 );
// Try to merge non-contiguous items of the same
// type together
for ( int m = l + 1 ; m <= r; ++m) {
if (arr[m] == arr[l]) {
ans = Math.max(
ans, dp(arr, m, r, k + 1 )
+ dp(arr, l + 1 , m - 1 , 0 ));
}
}
// Memoize the result and return it
return memo[lOriginal][r][kOriginal] = ans;
}
public static void main(String[] args)
{
int [] arr = { 1 , 3 , 2 , 2 , 2 , 3 , 4 , 3 , 1 };
int maxPoints = dp(arr, 0 , arr.length - 1 , 0 );
// Function Call
System.out.println( "Maximum points: " + maxPoints);
}
} |
# Function to calculate maximum points def dp(arr, l, r, k, memo):
# Base case: no elements left
if l > r:
return 0
# Return memoized result, if available
if memo[l][r][k] > 0 :
return memo[l][r][k]
l_orginal, k_orginal = l, k
while l + 1 < = r and arr[l] = = arr[l + 1 ]:
# Increase both `l` and `k` if they have
# consecutive identical items with `arr[l]`
l + = 1
k + = 1
# Option 1: Remove all elements which
# have the same item as `arr[l]`
ans = (k + 1 ) * (k + 1 ) + dp(arr, l + 1 , r, 0 , memo)
# Try to merge non-contiguous items of
# the same type together
for m in range (l + 1 , r + 1 ):
if arr[m] = = arr[l]:
ans = max (ans, dp(arr, m, r, k + 1 , memo) + dp(arr, l + 1 , m - 1 , 0 , memo))
# Memoize the result and return it
memo[l_orginal][r][k_orginal] = ans
return ans
# Driver code if __name__ = = "__main__" :
arr = [ 1 , 3 , 2 , 2 , 2 , 3 , 4 , 3 , 1 ]
n = len (arr)
memo = [[[ 0 ] * 200 for _ in range ( 200 )] for _ in range ( 200 )]
maxPoints = dp(arr, 0 , n - 1 , 0 , memo)
# Function Call
print (f "Maximum points: {maxPoints}" )
|
// C# Implementation using System;
public class MaximumPoints
{ // Memoization table to store computed results
static int [,,] memo = new int [200, 200, 200];
public static int Dp( int [] arr, int l, int r, int k)
{
// Base case: no elements left
if (l > r)
return 0;
// Return memoized result, if available.
if (memo[l, r, k] > 0)
return memo[l, r, k];
int lOriginal = l, kOriginal = k;
while (l + 1 <= r && arr[l] == arr[l + 1])
{
// Increase both `l` and `k` if they have
// consecutive identical items with `arr[l]`
l += 1;
k += 1;
}
// Option 1: Remove all elements which have the same
// item as `arr[l]`
int ans = (k + 1) * (k + 1) + Dp(arr, l + 1, r, 0);
// Try to merge non-contiguous items of the same
// type together
for ( int m = l + 1; m <= r; ++m)
{
if (arr[m] == arr[l])
{
ans = Math.Max(
ans, Dp(arr, m, r, k + 1)
+ Dp(arr, l + 1, m - 1, 0));
}
}
// Memoize the result and return it
return memo[lOriginal, r, kOriginal] = ans;
}
public static void Main( string [] args)
{
int [] arr = { 1, 3, 2, 2, 2, 3, 4, 3, 1 };
int maxPoints = Dp(arr, 0, arr.Length - 1, 0);
// Function Call
Console.WriteLine( "Maximum points: " + maxPoints);
}
} // This code is contributed by Tapesh(tapeshdua420) |
let memo = new Array(200).fill( null ).map(() =>
new Array(200).fill( null ).map(() => new Array(200).fill(0))
); function GFG(arr, l, r, k) {
// Base case: no elements left
if (l > r) return 0;
// Return memoized result
if (memo[l][r][k] > 0) return memo[l][r][k];
let lOriginal = l,
kOriginal = k;
while (l + 1 <= r && arr[l] === arr[l + 1]) {
// Increase both `l` and `k` if they have
l += 1;
k += 1;
}
// Option 1: Remove all elements which have the same item as `arr[l]`
let ans = (k + 1) * (k + 1) + GFG(arr, l + 1, r, 0);
// Try to merge non-contiguous items of the same type together
for (let m = l + 1; m <= r; ++m) {
if (arr[m] === arr[l]) {
ans = Math.max(
ans,
GFG(arr, m, r, k + 1) + GFG(arr, l + 1, m - 1, 0)
);
}
}
// Memoize the result and return it
return (memo[lOriginal][r][kOriginal] = ans);
} let arr = [1, 3, 2, 2, 2, 3, 4, 3, 1]; let maxPoints = GFG(arr, 0, arr.length - 1, 0); // Function Call console.log( "Maximum points: " + maxPoints);
|
Maximum points: 23
Time Complexity: O(N4), there are total N3 dp states, each state needs a loop O(N) to compute the result. So total complexity is O(N4).
Auxiliary Space: O(N3)