Open In App

Minimizing queries for winning segments in Binary Array

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:

Below is the implementation of the above approach:




#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;
}




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




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))




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 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)


Article Tags :