Skip to content
Related Articles

Related Articles

Improve Article

Partition the array in K segments such that bitwise AND of individual segment sum is maximized

  • Difficulty Level : Hard
  • Last Updated : 09 Aug, 2021
Geek Week

Given an array of size N and an integer K. The task is to partition the array in K segments such that bitwise AND of individual segment sum is maximized. Find the maximum value of bitwise AND which can be obtained.
 

Examples: 
 

Input : a[] = { 2, 5, 6, 9, 1, 3, 10, 12 }, K = 3 
Output :
Explanation : 
Maximum bitwise AND can be obtained by making cut at 3rd element and 5th element(1 based indexing) 
(2+5+6)&(9+1)&(3+10+12) = 8
Input : a[] = { 1, 2, 7, 10, 23, 21, 6, 8, 7, 3 } , K = 2 
Output : 41 
Explanation
Maximum bitwise AND can be obtained by making cut at 5th element(1 based indexing) 
(1+2+7+10+23)&(21+6+8+7+3) = 41

 



Approach: 
First, try to answer a simpler question: given an integer x and determine if it is possible to partition the given array into K segments such that the bitwise AND of sum of segments has all set bits of x
Let’s denote the sum of elements in the ith segment by S\textsubscript{i}   . Also, let’s call a segment good if S\textsubscript{i}   has all set bits of x. It’s clear now that for a good segment i, AND(S\textsubscript{i}   , x)=x
Also, all K segments should be good for getting bitwise AND of x. Now to check whether we can partition the array into k good segments. We can use dynamic programming here. 
Let dp[i][j]= true, denote that it is possible to partition first i elements into j segments such that all j are good segments otherwise false
The recurrence for above dp is: 
 

dp[i][j] is 1, if for some index k<i, AND(sum of a[k+1]…a[i], x)=x and dp[k][j-1]=1. Otherwise, dp[i][j] is 0

Build the dp table starting from the most significant bit of the possible answer greedily.
Below is the implementation of the above approach: 
 

C++




// CPP program to find maximum possible AND
#include <bits/stdc++.h>
using namespace std;
 
// Function to check whether a k segment partition
// is possible such that bitwise AND is 'mask'
bool checkpossible(int mask, int* arr, int* prefix, int n,
                                                  int k)
{
    // dp[i][j] stores whether it is possible to partition
    // first i elements into j segments such that all j
    // segments are 'good'
    bool dp[n + 1][k + 1];
 
    // Initialising dp
    memset(dp, 0, sizeof(dp));
    dp[0][0] = 1;
 
    // Filling dp in bottom-up manner
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= k; j++) {
            // Finding a cut such that first l elements
            // can be partitioned into j-1 'good' segments
            // and arr[l+1]+...+arr[i] is a 'good' segment
            for (int l = i - 1; l >= 0; --l) {
                if (dp[l][j - 1] && (((prefix[i] - prefix[l])
                           & mask) == mask)) {
                    dp[i][j] = 1;
                    break;
                }
            }
        }
    }
 
    return dp[n][k];
}
 
// Function to find maximum possible AND
int Partition(int arr[], int n, int k)
{
    // Array to store prefix sums
    int prefix[n+1];
 
    for (int i = 1; i <= n; i++) {
        prefix[i] = prefix[i - 1] + arr[i];
    }
 
    // Maximum no of bits in the possible answer
    int LOGS = 20;
 
    // This will store the final answer
    int ans = 0;
 
    // Constructing answer greedily selecting
    // from the higher most bit
    for (int i = LOGS; i >= 0; --i) {
        // Checking if array can be partitioned
        // such that the bitwise AND is ans|(1<<i)
        if (checkpossible(ans | (1 << i), arr, prefix, n, k))
        {
            // if possible, update the answer
            ans = ans | (1 << i);
        }
    }
 
    // Return the final answer
    return ans;
}
 
// Driver code
int main()
{
     
    int arr[]={0, 1, 2, 7, 10, 23, 21, 6, 8, 7, 3}, k = 2;
 
    // n = 11 , first element is zero
    // to make array 1 based indexing. So, number of
    // elements are 10
    int n = sizeof(arr)/sizeof(arr[0])-1;
     
    // Function call
    cout << Partition(arr, n, k);
     
    return 0;
}

Java




// Java program to find maximum possible AND
 
class GFG
{
     
    // Function to check whether a k segment partition
    // is possible such that bitwise AND is 'mask'
    static boolean checkpossible(int mask, int arr[],
                                int prefix[], int n, int k)
    {
        int i,j;
         
        // dp[i][j] stores whether it is possible to partition
        // first i elements into j segments such that all j
        // segments are 'good'
        boolean dp[][] = new boolean[n + 1][k + 1];
     
        // Initialising dp
        for(i = 0; i < n + 1; i++)
        {
            for(j = 0; j < k + 1; j++)
            {
                dp[i][j] = false ;
            }
        }
         
        dp[0][0] = true;
     
        // Filling dp in bottom-up manner
        for ( i = 1; i <= n; i++)
        {
            for (j = 1; j <= k; j++)
            {
                // Finding a cut such that first l elements
                // can be partitioned into j-1 'good' segments
                // and arr[l+1]+...+arr[i] is a 'good' segment
                for (int l = i - 1; l >= 0; --l)
                {
                    if (dp[l][j - 1] && (((prefix[i] - prefix[l])
                            & mask) == mask))
                    {
                        dp[i][j] = true;
                        break;
                    }
                }
            }
        }
     
        return dp[n][k];
    }
     
    // Function to find maximum possible AND
    static int Partition(int arr[], int n, int k)
    {
        // Array to store prefix sums
        int prefix[] = new int[n+1];
     
        for (int i = 1; i <= n; i++)
        {
            prefix[i] = prefix[i - 1] + arr[i];
        }
     
        // Maximum no of bits in the possible answer
        int LOGS = 20;
     
        // This will store the final answer
        int ans = 0;
     
        // Constructing answer greedily selecting
        // from the higher most bit
        for (int i = LOGS; i >= 0; --i)
        {
            // Checking if array can be partitioned
            // such that the bitwise AND is ans|(1<<i)
            if (checkpossible(ans | (1 << i), arr, prefix, n, k))
            {
                // if possible, update the answer
                ans = ans | (1 << i);
            }
        }
     
        // Return the final answer
        return ans;
    }
 
    // Driver code
    public static void main (String[] args)
    {
         
        int arr[] = {0, 1, 2, 7, 10, 23, 21, 6, 8, 7, 3}, k = 2;
     
        // n = 11 , first element is zero
        // to make array 1 based indexing. So, number of
        // elements are 10
        int n = arr.length - 1 ;
         
        // Function call
        System.out.println(Partition(arr, n, k));
    }
}
 
// This code is contributed by AnkitRai01

Python3




# Python3 program to find maximum possible AND
 
# Function to check whether a k segment partition
# is possible such that bitwise AND is 'mask'
def checkpossible(mask,arr,prefix, n,k):
     
    # dp[i][j] stores whether it is possible to partition
    # first i elements into j segments such that all j
    # segments are 'good'
    dp=[[0 for i in range(k+1)] for i in range(n + 1)]
 
    # Initialising dp
    dp[0][0] = 1
 
    # Filling dp in bottom-up manner
    for i in range(1, n+1):
        for j in range(1, k+1):
             
            # Finding a cut such that first l elements
            # can be partitioned into j-1 'good' segments
            # and arr[l+1]+...+arr[i] is a 'good' segment
            for l in range(i-1,-1,-1):
                if (dp[l][j - 1] and (((prefix[i] - prefix[l]) & mask) == mask)):
                    dp[i][j] = 1
                    break
 
    return dp[n][k]
 
 
# Function to find maximum possible AND
def Partition(arr, n, k):
    # Array to store prefix sums
    prefix=[0 for i in range(n+1)]
 
    for i in range(1,n+1):
        prefix[i] = prefix[i - 1] + arr[i]
 
    # Maximum no of bits in the possible answer
    LOGS = 20
 
    # This will store the final answer
    ans = 0
 
    # Constructing answer greedily selecting
    # from the higher most bit
    for i in range(LOGS,-1,-1):
        # Checking if array can be partitioned
        # such that the bitwise AND is ans|(1<<i)
        if (checkpossible(ans | (1 << i), arr, prefix, n, k)):
            # if possible, update the answer
            ans = ans | (1 << i)
 
 
    # Return the final answer
    return ans
 
 
# Driver code
 
arr = [0, 1, 2, 7, 10, 23, 21, 6, 8, 7, 3]
k = 2
 
# n = 11 , first element is zero
# to make array 1 based indexing. So, number of
# elements are 10
n = len(arr)-1
 
# Function call
print(Partition(arr, n, k))
 
# This code is contributed by mohit kumar 29

C#




// C# program to find maximum possible AND
using System;
     
class GFG
{
     
    // Function to check whether a
    // k-segment partition is possible
    // such that bitwise AND is 'mask'
    static Boolean checkpossible(int mask, int []arr,
                                 int []prefix,
                                 int n, int k)
    {
        int i, j;
         
        // dp[i,j] stores whether it is possible
        // to partition first i elements into
        // j-segments such that all j-segments are 'good'
        Boolean[,] dp = new Boolean[n + 1, k + 1];
     
        // Initialising dp
        for(i = 0; i < n + 1; i++)
        {
            for(j = 0; j < k + 1; j++)
            {
                dp[i, j] = false;
            }
        }
         
        dp[0, 0] = true;
     
        // Filling dp in bottom-up manner
        for ( i = 1; i <= n; i++)
        {
            for (j = 1; j <= k; j++)
            {
                // Finding a cut such that first l elements
                // can be partitioned into j-1 'good' segments
                // and arr[l+1]+...+arr[i] is a 'good' segment
                for (int l = i - 1; l >= 0; --l)
                {
                    if (dp[l, j - 1] &&
                     (((prefix[i] - prefix[l]) &
                        mask) == mask))
                    {
                        dp[i, j] = true;
                        break;
                    }
                }
            }
        }
        return dp[n, k];
    }
     
    // Function to find maximum possible AND
    static int Partition(int []arr, int n, int k)
    {
        // Array to store prefix sums
        int []prefix = new int[n + 1];
     
        for (int i = 1; i <= n; i++)
        {
            prefix[i] = prefix[i - 1] + arr[i];
        }
     
        // Maximum no of bits in the possible answer
        int LOGS = 20;
     
        // This will store the final answer
        int ans = 0;
     
        // Constructing answer greedily selecting
        // from the higher most bit
        for (int i = LOGS; i >= 0; --i)
        {
            // Checking if array can be partitioned
            // such that the bitwise AND is ans|(1<<i)
            if (checkpossible(ans | (1 << i),
                          arr, prefix, n, k))
            {
                // if possible, update the answer
                ans = ans | (1 << i);
            }
        }
     
        // Return the final answer
        return ans;
    }
 
    // Driver code
    public static void Main (String[] args)
    {
         
        int []arr = {0, 1, 2, 7, 10, 23,
                         21, 6, 8, 7, 3};
        int k = 2;
     
        // n = 11 , first element is zero
        // to make array 1 based indexing.
        // So, number of elements are 10
        int n = arr.Length - 1 ;
         
        // Function call
        Console.WriteLine(Partition(arr, n, k));
    }
}
 
// This code is contributed by 29AjayKumar

Javascript




<script>
    // Javascript program to find maximum possible AND
     
    // Function to check whether a k segment partition
    // is possible such that bitwise AND is 'mask'
    function checkpossible(mask, arr, prefix, n, k)
    {
        let i,j;
           
        // dp[i][j] stores whether it is possible to partition
        // first i elements into j segments such that all j
        // segments are 'good'
        let dp = new Array(n + 1);
       
        // Initialising dp
        for(i = 0; i < n + 1; i++)
        {
            dp[i] = new Array(k + 1);
            for(j = 0; j < k + 1; j++)
            {
                dp[i][j] = false ;
            }
        }
           
        dp[0][0] = true;
       
        // Filling dp in bottom-up manner
        for (i = 1; i <= n; i++)
        {
            for (j = 1; j <= k; j++)
            {
                // Finding a cut such that first l elements
                // can be partitioned into j-1 'good' segments
                // and arr[l+1]+...+arr[i] is a 'good' segment
                for (let l = i - 1; l >= 0; --l)
                {
                    if (dp[l][j - 1] && (((prefix[i] - prefix[l])
                            & mask) == mask))
                    {
                        dp[i][j] = true;
                        break;
                    }
                }
            }
        }
       
        return dp[n][k];
    }
       
    // Function to find maximum possible AND
    function Partition(arr, n, k)
    {
        // Array to store prefix sums
        let prefix = new Array(n+1);
        prefix.fill(0);
       
        for (let i = 1; i <= n; i++)
        {
            prefix[i] = prefix[i - 1] + arr[i];
        }
       
        // Maximum no of bits in the possible answer
        let LOGS = 20;
       
        // This will store the final answer
        let ans = 0;
       
        // Constructing answer greedily selecting
        // from the higher most bit
        for (let i = LOGS; i >= 0; --i)
        {
            // Checking if array can be partitioned
            // such that the bitwise AND is ans|(1<<i)
            if (checkpossible(ans | (1 << i), arr, prefix, n, k))
            {
                // if possible, update the answer
                ans = ans | (1 << i);
            }
        }
       
        // Return the final answer
        return ans;
    }
     
    let arr = [0, 1, 2, 7, 10, 23, 21, 6, 8, 7, 3], k = 2;
       
    // n = 11 , first element is zero
    // to make array 1 based indexing. So, number of
    // elements are 10
    let n = arr.length - 1 ;
 
    // Function call
    document.write(Partition(arr, n, k));
 
// This code is contributed by divyeshrabadiya07.
</script>
Output: 
41

 

Time Complexity : O(n^2   klog(S)), where S = S\textsubscript{1}   +S\textsubscript{2}   +….+S\textsubscript{k}   .
 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.  To complete your preparation from learning a language to DS Algo and many more,  please refer Complete Interview Preparation Course.

In case you wish to attend live classes with experts, please refer DSA Live Classes for Working Professionals and Competitive Programming Live for Students.




My Personal Notes arrow_drop_up
Recommended Articles
Page :