Open In App

Minimizing queries for winning segments in Binary Array

Last Updated : 02 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given array A[] of size N with all elements zero, along with given M segments in the form of array B[][2]. You have q queries in array Q[] in ith query you have to turn Q[i]th element of A[] into 1, the task for this problem is to find the minimum number of queries to have at least one segment from M segments in which the number of 1’s in the segment strictly greater than the number of zeros.

Examples:

Input: N = 5, B[][2] = {{1, 2}, {4, 5}, {1, 5}, {1, 3}, {2, 4}}, Q[] = {5, 3, 1, 2, 4}
Output: 3
Explanation: Initially A[] = {0, 0, 0, 0, 0}

  • For the first query, Q[1] = 5 so turn Q[1]’th index of array A[] one. A[] becomes {0, 0, 0, 0, 1}. After performing this query still, there is no segment from M segments that has more 1’s than 0’s.
  • For the second query, Q[2] = 3 so turn Q[2]’th index of array A[] one. A[] becomes {0, 0, 1, 0, 1}. After performing this query still, there is no segment from M segments that has more 1’s than 0’s.
  • For the third query, Q[3] = 1 so turn Q[3]’th index of array A[] one. A[] becomes {1, 0, 1, 0, 1}. After performing this query segments B[3] = {1, 5} and B[4] = {1, 3} has more 1’s than 0’s.

So the minimum number of queries to have at least one segment with more 1’s than 0’s is 3.

Input: N = 5, B[][2] = {{1, 5}, {1, 3}}, Q[] = {4, 1, 2, 3, 5}
Output: 3

Naïve Approach: The basic way to solve the problem is as follows:

This can be done in each query checking for all segments whether it has more 1’s than 0’s.

Time Complexity: O(N * M * Q)
Auxiliary Space: O(1)

Efficient Approach: To solve the problem follow the below idea:

  • Binary Search can be used to solve this problem. function f(n) is true if after n’th query at least one segment from M segments has more 1’s than 0’s else f(n) will be false. This is monotonic function of type “FFFTTTT”. Using binary search lets find first time when this function will become true that will be answer of this problem.
  • To check if given segment has more 1’s than 0’s prefix sum array can be used to check for each M segment in O(1) time complexity.

Below are the steps for the above approach:

  • check() function checks if there is at least one segment with more 1’s than 0’s within the first mid queries.
  • It initializes an array pre of size N+1 to store the prefix sum of 1’s from the queries.
  • It sets the first mid elements of pre to 1, indicating the 1’s from the first mid queries.
  • It then computes the prefix sum of the pre array.
  • For each segment in B, it calculates the number of 1’s and 0’s within that segment.
    • If there is at least one segment with more 1’s than 0’s, it returns true.
    • Otherwise, it returns false.
  • findMinimumQueries function finds the minimum number of queries required to have at least one segment with more 1’s than 0’s within the given M segments.
  • It initializes low to 1 and high to q for binary search.
  • Inside the loop, it calculates the middle value mid as the average of low and high.
  • It then calls the check() function with mid as an argument to check if there’s at least one segment with more 1’s than 0’s within the first mid queries.
    • If such a segment exists, it updates high to mid.
    • If not, it updates low to mid + 1.
  • Return the stored minimum queries in the end.

Below is the implementation of the above approach:

C++




#include <bits/stdc++.h>
using namespace std;
 
// Function to check if queries are performed
// till mid will there be at least one segment
// with more 1's than 0's
bool check(int mid, int N, int B[][2], int M, int Q[])
{
 
    // Creating array pre[] of size N
    vector<int> pre(N + 1, 0);
 
    // Performing first mid queries
    for (int i = 0; i < mid; i++)
        pre[Q[i]] = 1;
 
    // Forming prefix sum of this array
    for (int i = 1; i <= N; i++)
        pre[i] = pre[i] + pre[i - 1];
 
    // Checking if given M segments
    for (int i = 0; i < M; i++) {
 
        // Size of the given segment
        int sizeOfSegment = B[i][1] - B[i][0] + 1;
 
        // Number of one's it has
        int numberOfOnes = pre[B[i][1]] - pre[B[i][0] - 1];
 
        // Number of zeros it has
        int numberOfZeros = sizeOfSegment - numberOfOnes;
 
        // If the number of one's is greater than
        // zero's then return true
        if (numberOfOnes > numberOfZeros)
            return true;
    }
 
    // If the number of one's is not greater than
    // zero's then return false
    return false;
}
 
// Function to find Minimum number of queries
// to have at least one segment with more 1's
// than 0's from given M segments
int findMinimumQueries(int N, int B[][2], int M, int Q[],
                       int q)
{
 
    // Range of binary search
    int low = 1, high = q;
    int min_query = 0;
 
    // Running a loop until high
    // is not equal to low
    while (high - low > 1) {
 
        // mid is the average of low and high
        int mid = (low + high) / 2;
 
        // Checking the test function
        if (check(mid, N, B, M, Q)) {
            min_query = mid;
            high = mid - 1;
        }
        else {
            low = mid + 1;
        }
    }
 
    return min_query;
}
 
// Driver Code
int main()
{
 
    // Input 1
    int N = 5;
    int B[][2] = { { 1, 2 },
                   { 4, 5 },
                   { 1, 5 },
                   { 1, 3 },
                   { 2, 4 } };
    int M = 5;
    int Q[] = { 5, 3, 1, 2, 4 };
    int q = 5;
 
    // Function Call
    cout << findMinimumQueries(N, B, M, Q, q) << endl;
 
    // Input 2
    int N1 = 5;
    int B1[][2] = { { 1, 5 }, { 1, 3 } };
    int M1 = 2;
    int Q1[] = { 4, 1, 2, 3, 5 };
    int q1 = 5;
 
    // Function Call
    cout << findMinimumQueries(N1, B1, M1, Q1, q1) << endl;
 
    return 0;
}


Java




import java.util.*;
 
class Main {
    // Function to check if queries are performed
    // till mid will there be at least one segment
    // with more 1's than 0's
    static boolean check(int mid, int N, int[][] B, int M, int[] Q) {
        // Creating array pre[] of size N
        int[] pre = new int[N + 1];
 
        // Performing first mid queries
        for (int i = 0; i < mid; i++)
            pre[Q[i]] = 1;
 
        // Forming prefix sum of this array
        for (int i = 1; i <= N; i++)
            pre[i] = pre[i] + pre[i - 1];
 
        // Checking if given M segments
        for (int i = 0; i < M; i++) {
            // Size of given segment
            int sizeOfSegment = B[i][1] - B[i][0] + 1;
 
            // Number of one's it has
            int numberOfOnes = pre[B[i][1]] - pre[B[i][0] - 1];
 
            // Number of zeros it has
            int numberOfZeros = sizeOfSegment - numberOfOnes;
 
            // If number of one's is greater than
            // zero's than return true
            if (numberOfOnes > numberOfZeros)
                return true;
        }
 
        // If number of one's is not greater than
        // zero's than return false
        return false;
    }
 
    // Function to find Minimum number of queries
    // to have at least one segment with more 1's
    // than 0's from given M segments
    static int findMinimumQueries(int N, int[][] B, int M, int[] Q, int q) {
        // Range of binary search
        int low = 1, high = q;
        int min_query = 0;
 
        // Running loop till high
        // is not equal to low
        while (high - low > 1) {
            // mid is average of low and high
            int mid = (low + high) / 2;
 
            // Checking test function
            if (check(mid, N, B, M, Q)) {
                min_query = mid;
                high = mid - 1;
            } else {
                low = mid + 1;
            }
        }
 
        return min_query;
    }
 
    // Driver Code
    public static void main(String[] args) {
        // Input 1
        int N = 5;
        int[][] B = { { 1, 2 }, { 4, 5 }, { 1, 5 }, { 1, 3 }, { 2, 4 } };
        int M = 5;
        int[] Q = { 5, 3, 1, 2, 4 };
        int q = 5;
 
        // Function Call
        System.out.println(findMinimumQueries(N, B, M, Q, q));
 
        // Input 2
        int N1 = 5;
        int[][] B1 = { { 1, 5 }, { 1, 3 } };
        int M1 = 2;
        int[] Q1 = { 4, 1, 2, 3, 5 };
        int q1 = 5;
 
        // Function Call
        System.out.println(findMinimumQueries(N1, B1, M1, Q1, q1));
    }
}
//This code is Contributed by chinmaya121221


Python




def check(mid, N, B, M, Q):
    # Creating a list pre[] of size N
    pre = [0] * (N + 1)
 
    # Performing first mid queries
    for i in range(mid):
        pre[Q[i]] = 1
 
    # Forming the prefix sum of this list
    for i in range(1, N + 1):
        pre[i] = pre[i] + pre[i - 1]
 
    # Checking if given M segments
    for i in range(M):
        # Size of the given segment
        size_of_segment = B[i][1] - B[i][0] + 1
 
        # Number of ones it has
        number_of_ones = pre[B[i][1]] - pre[B[i][0] - 1]
 
        # Number of zeros it has
        number_of_zeros = size_of_segment - number_of_ones
 
        # If the number of ones is greater than
        # the number of zeros, then return True
        if number_of_ones > number_of_zeros:
            return True
 
    # If the number of ones is not greater than
    # the number of zeros, then return False
    return False
 
 
def find_minimum_queries(N, B, M, Q, q):
    # Range of binary search
    low = 1
    high = q
    min_query = 0
 
    # Running a loop until high
    # is not equal to low
    while high - low > 1:
        # mid is the average of low and high
        mid = (low + high) // 2
 
        # Checking the test function
        if check(mid, N, B, M, Q):
            min_query = mid
            high = mid - 1
        else:
            low = mid + 1
 
    return min_query
 
 
# Driver Code
if __name__ == "__main__":
    # Input 1
    N = 5
    B = [[1, 2], [4, 5], [1, 5], [1, 3], [2, 4]]
    M = 5
    Q = [5, 3, 1, 2, 4]
    q = 5
 
    # Function Call
    print(find_minimum_queries(N, B, M, Q, q))
 
    # Input 2
    N1 = 5
    B1 = [[1, 5], [1, 3]]
    M1 = 2
    Q1 = [4, 1, 2, 3, 5]
    q1 = 5
 
    # Function Call
    print(find_minimum_queries(N1, B1, M1, Q1, q1))


C#




using System;
using System.Collections.Generic;
 
class Program
{
    // Function to check if queries are performed
    // till mid will there be at least one segment
    // with more 1's than 0's
    static bool Check(int mid, int N, int[][] B, int M, int[] Q)
    {
        // Creating array pre[] of size N
        List<int> pre = new List<int>(new int[N + 1]);
 
        // Performing first mid queries
        for (int i = 0; i < mid; i++)
            pre[Q[i]] = 1;
 
        // Forming prefix sum of this array
        for (int i = 1; i <= N; i++)
            pre[i] = pre[i] + pre[i - 1];
 
        // Checking if given M segments
        for (int i = 0; i < M; i++)
        {
            // Size of the given segment
            int sizeOfSegment = B[i][1] - B[i][0] + 1;
 
            // Number of one's it has
            int numberOfOnes = pre[B[i][1]] - pre[B[i][0] - 1];
 
            // Number of zeros it has
            int numberOfZeros = sizeOfSegment - numberOfOnes;
 
            // If the number of one's is greater than
            // zero's then return true
            if (numberOfOnes > numberOfZeros)
                return true;
        }
 
        // If the number of one's is not greater than
        // zero's then return false
        return false;
    }
 
    // Function to find Minimum number of queries
    // to have at least one segment with more 1's
    // than 0's from given M segments
    static int FindMinimumQueries(int N, int[][] B, int M, int[] Q, int q)
    {
        // Range of binary search
        int low = 1;
        int high = q;
        int min_query = 0;
 
        // Running a loop until high
        // is not equal to low
        while (high - low > 1)
        {
            // mid is the average of low and high
            int mid = (low + high) / 2;
 
            // Checking the test function
            if (Check(mid, N, B, M, Q))
            {
                min_query = mid;
                high = mid - 1;
            }
            else
            {
                low = mid + 1;
            }
        }
 
        return min_query;
    }
 
    // Driver Code
    static void Main()
    {
        // Input 1
        int N = 5;
        int[][] B = {
            new int[] {1, 2},
            new int[] {4, 5},
            new int[] {1, 5},
            new int[] {1, 3},
            new int[] {2, 4}
        };
        int M = 5;
        int[] Q = {5, 3, 1, 2, 4};
        int q = 5;
 
        // Function Call
        Console.WriteLine(FindMinimumQueries(N, B, M, Q, q));
 
        // Input 2
        int N1 = 5;
        int[][] B1 = {
            new int[] {1, 5},
            new int[] {1, 3}
        };
        int M1 = 2;
        int[] Q1 = {4, 1, 2, 3, 5};
        int q1 = 5;
 
        // Function Call
        Console.WriteLine(FindMinimumQueries(N1, B1, M1, Q1, q1));
    }
}
//Contributed by tyagdh0xk


Javascript




// JavaScript code to implement the approach
 
// Function to check if queries are performed
// till mid will there be at least one segment
// with more 1's than 0's
function check(mid, N, B, M, Q) {
  // Creating an array pre of size N
  const pre = new Array(N + 1).fill(0);
 
  // Performing the first mid queries
  for (let i = 0; i < mid; i++) {
    pre[Q[i]] = 1;
  }
 
  // Forming a prefix sum of this array
  for (let i = 1; i <= N; i++) {
    pre[i] = pre[i] + pre[i - 1];
  }
 
  // Checking if given M segments
  for (let i = 0; i < M; i++) {
    // Size of the given segment
    const sizeOfSegment = B[i][1] - B[i][0] + 1;
 
    // Number of ones it has
    const numberOfOnes = pre[B[i][1]] - pre[B[i][0] - 1];
 
    // Number of zeros it has
    const numberOfZeros = sizeOfSegment - numberOfOnes;
 
    // If the number of ones is greater than
    // the number of zeros, return true
    if (numberOfOnes > numberOfZeros) {
      return true;
    }
  }
 
  // If the number of ones is not greater than
  // the number of zeros, return false
  return false;
}
 
// Function to find Minimum number of queries
// to have at least one segment with more 1's
// than 0's from given M segments
function findMinimumQueries(N, B, M, Q, q) {
  // Range of binary search
  let low = 1;
  let high = q;
  let min_query = 0;
 
  // Running a loop until high
  // is not equal to low
  while (high - low > 1) {
    // mid is the average of low and high
    const mid = Math.floor((low + high) / 2);
 
    // Checking the test function
    if (check(mid, N, B, M, Q)) {
      min_query = mid;
      high = mid - 1;
    } else {
      low = mid + 1;
    }
  }
 
  return min_query;
}
 
// Driver Code
// Input 1
const N = 5;
const B = [[1, 2], [4, 5], [1, 5], [1, 3], [2, 4]];
const M = 5;
const Q = [5, 3, 1, 2, 4];
const q = 5;
 
// Function Call
console.log(findMinimumQueries(N, B, M, Q, q));
 
// Input 2
const N1 = 5;
const B1 = [[1, 5], [1, 3]];
const M1 = 2;
const Q1 = [4, 1, 2, 3, 5];
const q1 = 5;
 
// Function Call
console.log(findMinimumQueries(N1, B1, M1, Q1, q1));


Output

3
3










Time Complexity: O((N + M)*logQ)
Auxiliary Space: O(N)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads