Given N toys in a shop. The cost of each toy is represented by an array A[]. You are given Q queries, For ith query, you have a C amount of money which you can use to purchase the toys. Also, there are K broken toys and you won't purchase them. The task is to calculate the maximum number of toys you can purchase using the C amount of money. (1-based indexing is used. Each query is treated independently).
Query definition:
- The first element represents an integer C where C=Queries[i][0].
- The second element represents an integer K, where K = Queries[i][1].
- The next K integers represent the indices of broken toys which are Queries[i][j], j>1
Examples:
Input: N = 5, A[] = {8, 6, 9, 2, 5}, Q = 2, Query[][] = {{12, 2, 3, 4}, {30, 0}}
Output: 2 5
Explanation: Query 1: C = 12, K = 2,
Indices of Broken toys is {3, 4}.
Indices of Available toys are {1, 2, 5}. If we purchase the toys 2 and 5, then cost = A[2] + A[5] = 6 + 5 = 11, Therefore,We purchase the 2 toys using 11 amount of money.
Query 2: C = 30, K = 0.
There is no broken toy. We can purchase all toys, cost = A[1] + A[2] + A[3] + A[4] + A[5] = 30, Therefore,We purchase the 5 toys using 30 amount of money.Input: N = 2, A[] = {3, 3}, Q = 1, Query[][] = {{1, 0}}
Output: 0
Explanation: Query 1: C = 1, K = 0 , There is no broken toy. We have not enough amount to purchase any toy.
Approach: To solve the problem follow the below idea:
The idea is to use binary indexed trees (Fenwick trees) to efficiently solve queries on a set of bowls. It calculates sums, tracks frequencies, and adjusts values for discarded bowls in each query. The binary search identifies the position where the sum of values exceeds a limit, considering frequencies. The process is repeated for all queries, and the results are stored in a vector, which is returned as the final answer.
Step-by-step approch:
- Initialise two binary indexed tree or fenwick tree, b1 and b2. b1 will give the sum of the array while b2 will provide details about frequency.
- In each query, start iterating for all the discarded k bowls and update them as their negation in b1 and as -1 in b2.
- Use binary search to find the first position after which sum >= C (limit given). Simply add the sum of frequency till pos-1 in the answer, and for the remaining, add the minimum of (C - sum till (pos-1)) / pos and the frequency of pos.
- Update back to all k discarded bowls to their original value in both trees.
- Repeat the above for all queries and push all answers into a vector, res.
- Return res.
Below is the implementation of the above approach:
#include <iostream>
#include <vector>
using namespace std;
const int N = 1e6 + 5;
int fr[N]; // array to store the frequency of elements
class tree {
public:
vector<long long> bit; // Binary Indexed Tree
tree()
{
bit = vector<long long>(N); // initialize BIT
}
void add(int node, int v)
{
for (; node < N; node += (node & (-node)))
bit[node] += v; // updating BIT by adding v to
// each element
}
long long get(int node)
{
long long x = 0;
for (; node > 0; node -= (node & (-node)))
x += bit[node]; // sum of elements in BIT
return x;
}
};
tree obj1, obj2; // creating two instances of tree
vector<int> maximumToys(int N, vector<int> A, int Q,
vector<vector<int> > Queries)
{
vector<int> res;
for (auto i : A) {
fr[i]++; // counting the frequency of each element
// in A array
}
for (int i = 0; i < A.size(); i++) {
obj1.add(A[i], A[i]); // adding elements to bit1
obj2.add(A[i],
1); // adding 1 to bit2 for each element
}
for (auto i : Queries) {
long long C = i[0]; // value of C
for (int j = 2; j < i.size(); j++) {
obj1.add(A[i[j] - 1],
-A[i[j] - 1]); // removing the element
// from bit1
obj2.add(A[i[j] - 1],
-1); // decrementing 1 from bit2
}
long long lw = 1,
hg = 1e6; // lower bound and higher bound
long long pos = 1e6; // position
while (lw <= hg) {
int mid = (lw + hg) / 2;
if (obj1.get(mid)
>= C) { // check if the sum of elements till
// mid is greater or equal to C
pos = mid;
hg = mid - 1;
}
else {
lw = mid + 1;
}
}
long long ans = obj2.get(
pos
- 1); // get the sum till position-1 from bit2
long long mx = min(
(C - obj1.get(pos - 1)) / pos,
(long long)
fr[pos]); // find the maximum possible sum
ans += mx; // add the maximum sum to ans
res.push_back(ans); // push the answer to res
for (int j = 2; j < i.size(); j++) {
obj1.add(A[i[j] - 1],
A[i[j] - 1]); // add the element back
// to bit1
obj2.add(A[i[j] - 1], 1); // add 1 to bit2
}
}
for (int i = 0; i < A.size(); i++) {
obj1.add(A[i],
-A[i]); // remove the element from bit1
obj2.add(A[i], -1); // decrement 1 from bit2
fr[A[i]]--; // decrement the frequency of the
// element in fr array
}
return res; // return the result
}
int main()
{
vector<int> A = { 8, 6, 9, 2, 5 };
int Q = 2, N = 5;
vector<vector<int> > Queries
= { { 12, 2, 3, 4 }, { 30, 0 } };
vector<int> result = maximumToys(N, A, Q, Queries);
for (int val : result) {
cout << val << " ";
}
cout << endl;
return 0;
}
import java.util.ArrayList;
import java.util.List;
class Main {
static final int N = 1000005;
static int[] fr = new int[N]; // array to store the
// frequency of elements
static class Tree {
List<Long> bit; // Binary Indexed Tree
Tree()
{
bit = new ArrayList<>(N); // initialize BIT
for (int i = 0; i < N; i++) {
bit.add(0L);
}
}
void add(int node, int v)
{
for (; node < N; node += (node & (-node))) {
bit.set(node,
bit.get(node)
+ v); // updating BIT by adding
// v to each element
}
}
long get(int node)
{
long x = 0;
for (; node > 0; node -= (node & (-node))) {
x += bit.get(
node); // sum of elements in BIT
}
return x;
}
}
static Tree obj1 = new Tree();
static Tree obj2
= new Tree(); // creating two instances of Tree
static List<Integer>
maximumToys(int N, List<Integer> A, int Q,
List<List<Integer> > Queries)
{
List<Integer> res = new ArrayList<>();
for (int i : A) {
fr[i]++; // counting the frequency of each
// element in A array
}
for (int i = 0; i < A.size(); i++) {
obj1.add(A.get(i),
A.get(i)); // adding elements to bit1
obj2.add(
A.get(i),
1); // adding 1 to bit2 for each element
}
for (List<Integer> i : Queries) {
long C = i.get(0); // value of C
for (int j = 2; j < i.size(); j++) {
obj1.add(A.get(i.get(j) - 1),
-A.get(i.get(j)
- 1)); // removing the
// element from bit1
obj2.add(A.get(i.get(j) - 1),
-1); // decrementing 1 from bit2
}
long lw = 1,
hg
= 1000000; // lower bound and higher bound
long pos = 1000000; // position
while (lw <= hg) {
int mid = (int)((lw + hg) / 2);
if (obj1.get(mid)
>= C) { // check if the sum of elements
// till mid is greater or equal
// to C
pos = mid;
hg = mid - 1;
}
else {
lw = mid + 1;
}
}
long ans = obj2.get(
(int)(pos - 1)); // get the sum till
// position-1 from bit2
long mx = Math.min(
(C - obj1.get((int)(pos - 1))) / pos,
(long)fr[(int)pos]); // find the maximum
// possible sum
ans += mx; // add the maximum sum to ans
res.add((int)ans); // push the answer to res
for (int j = 2; j < i.size(); j++) {
obj1.add(
A.get(i.get(j) - 1),
A.get(i.get(j) - 1)); // add the element
// back to bit1
obj2.add(A.get(i.get(j) - 1),
1); // add 1 to bit2
}
}
for (int i = 0; i < A.size(); i++) {
obj1.add(
A.get(i),
-A.get(i)); // remove the element from bit1
obj2.add(A.get(i), -1); // decrement 1 from bit2
fr[A.get(i)]--; // decrement the frequency of
// the element in fr array
}
return res; // return the result
}
public static void main(String[] args)
{
List<Integer> A = List.of(8, 6, 9, 2, 5);
int Q = 2, N = 5;
List<List<Integer> > Queries
= List.of(List.of(12, 2, 3, 4), List.of(30, 0));
List<Integer> result
= maximumToys(N, A, Q, Queries);
for (int val : result) {
System.out.print(val + " ");
}
System.out.println();
}
}
class Tree:
def __init__(self):
self.bit = [0] * (10 ** 6 + 5)
def add(self, node, v):
# Update the Binary Indexed Tree (BIT) by adding v to each element
while node < len(self.bit):
self.bit[node] += v
node += node & -node
def get(self, node):
# Get the sum of elements in BIT up to the given node
x = 0
while node > 0:
x += self.bit[node]
node -= node & -node
return x
def maximum_toys(N, A, Q, Queries):
res = []
fr = [0] * (10 ** 6 + 5)
obj1 = Tree()
obj2 = Tree()
# Count the frequency of each element in array A
for i in A:
fr[i] += 1
# Build the initial Binary Indexed Trees (BITs)
for i in A:
obj1.add(i, i)
obj2.add(i, 1)
# Process each query in Queries
for i in Queries:
C = i[0] # Value of C
# Update BITs by removing elements specified in the query
for j in i[2:]:
obj1.add(A[j - 1], -A[j - 1])
obj2.add(A[j - 1], -1)
# Binary search to find the position where the sum is greater or equal to C
lw, hg = 1, 10 ** 6
pos = 10 ** 6
while lw <= hg:
mid = (lw + hg) // 2
if obj1.get(mid) >= C:
pos = mid
hg = mid - 1
else:
lw = mid + 1
# Calculate the maximum possible sum and update the result
ans = obj2.get(pos - 1)
mx = min((C - obj1.get(pos - 1)) // pos, fr[pos])
ans += mx
res.append(ans)
# Update BITs by adding back the removed elements
for j in i[2:]:
obj1.add(A[j - 1], A[j - 1])
obj2.add(A[j - 1], 1)
# Cleanup: Remove elements from BITs and decrement frequencies
for i in A:
obj1.add(i, -i)
obj2.add(i, -1)
fr[i] -= 1
return res
if __name__ == "__main__":
# Example input
A = [8, 6, 9, 2, 5]
Q = 2
N = 5
Queries = [[12, 2, 3, 4], [30, 0]]
# Get and print the result
result = maximum_toys(N, A, Q, Queries)
print(" ".join(map(str, result)))
using System;
using System.Collections.Generic;
class MainClass {
const int N = 1000005;
static int[] fr = new int[N]; // array to store the
// frequency of elements
class Tree {
List<long> bit; // Binary Indexed Tree
public Tree()
{
bit = new List<long>(N); // initialize BIT
for (int i = 0; i < N; i++) {
bit.Add(0L);
}
}
public void Add(int node, int v)
{
for (; node < N; node += (node & (-node))) {
bit[node] += v; // updating BIT by adding v
// to each element
}
}
public long Get(int node)
{
long x = 0;
for (; node > 0; node -= (node & (-node))) {
x += bit[node]; // sum of elements in BIT
}
return x;
}
}
static Tree obj1 = new Tree();
static Tree obj2
= new Tree(); // creating two instances of Tree
static List<int> MaximumToys(int N, List<int> A, int Q,
List<List<int> > Queries)
{
List<int> res = new List<int>();
foreach(int i in A)
{
fr[i]++; // counting the frequency of each
// element in A array
}
for (int i = 0; i < A.Count; i++) {
obj1.Add(A[i], A[i]); // adding elements to bit1
obj2.Add(
A[i],
1); // adding 1 to bit2 for each element
}
foreach(List<int> query in Queries)
{
long C = query[0]; // value of C
for (int j = 2; j < query.Count; j++) {
obj1.Add(
A[query[j] - 1],
-A[query[j] - 1]); // removing the
// element from bit1
obj2.Add(A[query[j] - 1],
-1); // decrementing 1 from bit2
}
long lw = 1,
hg
= 1000000; // lower bound and higher bound
long pos = 1000000; // position
while (lw <= hg) {
int mid = (int)((lw + hg) / 2);
if (obj1.Get(mid)
>= C) // check if the sum of elements
// till mid is greater or equal to
// C
{
pos = mid;
hg = mid - 1;
}
else {
lw = mid + 1;
}
}
long ans = obj2.Get(
(int)(pos - 1)); // get the sum till
// position-1 from bit2
long mx = Math.Min(
(C - obj1.Get((int)(pos - 1))) / pos,
fr[(int)pos]); // find the maximum possible
// sum
ans += mx; // add the maximum sum to ans
res.Add((int)ans); // push the answer to res
for (int j = 2; j < query.Count; j++) {
obj1.Add(
A[query[j] - 1],
A[query[j]
- 1]); // add the element back to bit1
obj2.Add(A[query[j] - 1],
1); // add 1 to bit2
}
}
for (int i = 0; i < A.Count; i++) {
obj1.Add(A[i],
-A[i]); // remove the element from bit1
obj2.Add(A[i], -1); // decrement 1 from bit2
fr[A[i]]--; // decrement the frequency of the
// element in fr array
}
return res; // return the result
}
public static void Main(string[] args)
{
List<int> A = new List<int>{ 8, 6, 9, 2, 5 };
int Q = 2, N = 5;
List<List<int> > Queries = new List<List<int> >{
new List<int>{ 12, 2, 3, 4 },
new List<int>{ 30, 0 }
};
List<int> result = MaximumToys(N, A, Q, Queries);
foreach(int val in result)
{
Console.Write(val + " ");
}
Console.WriteLine();
}
}
// Define a class for Binary Indexed Tree (BIT)
class Tree {
constructor() {
// Initialize the BIT array with zeros
this.bit = new Array(1000005).fill(0);
}
// Method to update the BIT by adding a value to each element
add(node, v) {
while (node < this.bit.length) {
this.bit[node] += v;
node += node & -node;
}
}
// Method to get the sum of elements in BIT up to the given node
get(node) {
let x = 0;
while (node > 0) {
x += this.bit[node];
node -= node & -node;
}
return x;
}
}
// Function to solve the problem
function maximumToys(N, A, Q, Queries) {
// Initialize an array to store the results
const res = [];
// Initialize an array to keep track of element frequencies
const fr = new Array(1000005).fill(0);
// Create instances of the Tree class for two BITs
const obj1 = new Tree();
const obj2 = new Tree();
// Count the frequency of each element in array A
for (let i = 0; i < A.length; i++) {
fr[A[i]] += 1;
}
// Build the initial Binary Indexed Trees (BITs)
for (let i = 0; i < A.length; i++) {
obj1.add(A[i], A[i]);
obj2.add(A[i], 1);
}
// Process each query in Queries
for (let i = 0; i < Q; i++) {
// Extract the value of C from the current query
const C = Queries[i][0];
// Update BITs by removing elements specified in the query
for (let j = 2; j < Queries[i].length; j++) {
obj1.add(A[Queries[i][j] - 1], -A[Queries[i][j] - 1]);
obj2.add(A[Queries[i][j] - 1], -1);
}
// Binary search to find the position where the sum is greater or equal to C
let lw = 1, hg = 1000000;
let pos = 1000000;
while (lw <= hg) {
const mid = Math.floor((lw + hg) / 2);
if (obj1.get(mid) >= C) {
pos = mid;
hg = mid - 1;
} else {
lw = mid + 1;
}
}
// Calculate the maximum possible sum and update the result
const ans = obj2.get(pos - 1);
const mx = Math.min((C - obj1.get(pos - 1)) / pos | 0, fr[pos]);
res.push(ans + mx);
// Update BITs by adding back the removed elements
for (let j = 2; j < Queries[i].length; j++) {
obj1.add(A[Queries[i][j] - 1], A[Queries[i][j] - 1]);
obj2.add(A[Queries[i][j] - 1], 1);
}
}
// Cleanup: Remove elements from BITs and decrement frequencies
for (let i = 0; i < A.length; i++) {
obj1.add(A[i], -A[i]);
obj2.add(A[i], -1);
fr[A[i]] -= 1;
}
// Return the final results
return res;
}
// Example input
const A = [8, 6, 9, 2, 5];
const Q = 2;
const N = 5;
const Queries = [
[12, 2, 3, 4],
[30, 0]
];
// Get and print the result
const result = maximumToys(N, A, Q, Queries);
console.log(result.join(" "));
Output
2 5
Time Complexity: O(NLogMx + Q*K*LogMx + Q*(LogMx)^2)
Auxiliary Space: O(Mx), Where Mx is the maximum element present in the array A[i].