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 : 8
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
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:
// 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 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 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# 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 |
<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
.
Performance Analysis:
Time Complexity: O(20*n2k) in the worst case.
Space Complexity: O(n*k) in worst case.