Given integers N and K representing the number of batches and number of students in each batch respectively, and a 2D array ratings[][] of size N * K where each row has ratings for every K students and Q queries of type {a, b}. The task for each query is to count the number of groups of N students possible by selecting a student from each batch, such that sum of ratings in each group lies in the range [a, b] inclusively.
Examples:
Input: N = 2, K = 3, ratings[][]= { {1, 2, 3}, {4, 5, 6} }, Q = 2, Queries[][]={ {6, 6}, {1, 6} }
Output: 2 3
Explanation:
All possible groups of size N(=2) are:
1 + 4 = 5
1 + 5 = 6
1 + 6 = 7
2 + 4 = 6
2 + 5 = 7
2 + 6 = 8
3 + 4 = 7
3 + 5 = 8
3 + 6 = 9
Query 1: The groups whose sum in range of (6, 6) inclusive are (1 + 5), (2 + 4) is 2.
Query 2:Â The groups whose sum in range of (1, 6) inclusive are (1 + 4), (1 + 5), (2 + 4) is 3.Input: N = 3, K = 3, ratings[][]={ {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }, Q = 2, Queries[][]={ {10, 13}, {1, 7} }
Output: 4 0
Explanation:
Out of All possible groups of size N(=3):
Query 1:Â The groups whose sum in range (10, 13) inclusive is (1 + 4 + 7), (1 + 5 + 7), (2 + 4 + 7), (1 + 4 + 8) is 4.
Query 2: The groups whose sum in range of (1, 7) inclusive is  0.
Â
Naive Approach: The simplest approach is to use recursion to generate all possible groups of size N. At each step of recursion calculate the sum that lies within the range of a query and find the number of groups that lie in the given range.
Time Complexity: O(NK)
Auxiliary Space: O(1)
Efficient Approach: The above approach can be optimized by using Dynamic Programming. The idea is that if the number of times the sum S appears in the ith row is known, then the Prefix Sum Technique can be used to answer all the queries in constant time. So in this way, the Overlapping Subproblems are calculated only once reducing the exponential time into polynomial time. Below are the steps:
- Initialize auxiliary array dp[][] where dp[i][sum] is the number of times a sum is present in the ith row.
- For each batch, i iterate through all possible sum S, and for each j students, if sum S is greater than the current rating ratings[i][j] then update the current dp state dp[i][S] as:
dp[i][S] = dp[i][S] + dp[i – 1][sum – rating[i][j]]
- After the above steps, dp[N – 1][sum], which is the number of times the sum appears in the (N – 1)th row.
- To answer each queries efficiently find the prefix sum of the last row i.e., dp[N – 1][S] for all values of sum S.
- Now, the number of ways to form groups in the given range [a, b] is dp[N – 1][b] – dp[N – 1][a – 1].
Below is the implementation of the above approach: Â Â
C++
// C++ program for the above approachÂ
#include <bits/stdc++.h>using namespace std;Â
// Given n batches and k students#define n 2#define k 3Â
// Function to count number of// ways to get given sum groupsvoid numWays(int ratings[n][k], int queries[][2]){Â
    // Initialise dp array    int dp[n][10000 + 2];Â
    // Mark all 1st row values as 1    // since the mat[0][i] is all    // possible sums in first row    for (int i = 0; i < k; i++)        dp[0][ratings[0][i]] += 1;Â
    // Fix the ith row    for (int i = 1; i < n; i++) {Â
        // Fix the sum        for (int sum = 0; sum <= 10000; sum++)         {            // Iterate through all            // values of ith row            for (int j = 0; j < k; j++)             {                // If sum can be obtained                if (sum >= ratings[i][j])                    dp[i][sum]                        += dp[i - 1][sum - ratings[i][j]];            }        }    }Â
    // Find the prefix sum of last row    for (int sum = 1; sum <= 10000; sum++)     {        dp[n - 1][sum] += dp[n - 1][sum - 1];    }Â
    // Traverse each queryÂ
    for (int q = 0; q < 2; q++)     {        int a = queries[q][0];        int b = queries[q][1];Â
        // No of ways to form groups        cout << dp[n - 1][b] - dp[n - 1][a - 1] << " ";    }}Â
// Driver Codeint main(){Â
    // Given ratings    int ratings[n][k] = { { 1, 2, 3 }, { 4, 5, 6 } };Â
    // Given Queries    int queries[][2] = { { 6, 6 }, { 1, 6 } };Â
    // Function Call    numWays(ratings, queries);Â
    return 0;} |
Java
// Java program for the above approachÂ
import java.util.*;public class Main {Â
    // Function to count number of    // ways to get given sum groups    public static void    numWays(int[][] ratings,             int queries[][],             int n, int k)    {Â
        // Initialise dp array        int dp[][] = new int[n][10000 + 2];Â
        // Mark all 1st row values as 1        // since the mat[0][i] is all        // possible sums in first row        for (int i = 0; i < k; i++)            dp[0][ratings[0][i]] += 1;Â
        // Fix the ith row        for (int i = 1; i < n; i++)         {Â
            // Fix the sum            for (int sum = 0; sum <= 10000; sum++)             {Â
                // Iterate through all                // values of ith row                for (int j = 0; j < k; j++)                 {Â
                    // If sum can be obtained                    if (sum >= ratings[i][j])                        dp[i][sum]                            += dp[i - 1]                               [sum - ratings[i][j]];                }            }        }Â
        // Find the prefix sum of last row        for (int sum = 1; sum <= 10000; sum++) {            dp[n - 1][sum] += dp[n - 1][sum - 1];        }Â
        // Traverse each query        for (int q = 0; q < queries.length; q++) {Â
            int a = queries[q][0];            int b = queries[q][1];Â
            // No of ways to form groups            System.out.print(dp[n - 1][b] - dp[n - 1][a - 1]                             + " ");        }    }Â
    // Driver Code    public static void main(String args[])    {        // Given N batches and K students        int N = 2, K = 3;Â
        // Given ratings        int ratings[][] = { { 1, 2, 3 }, { 4, 5, 6 } };Â
        // Given Queries        int queries[][] = { { 6, 6 }, { 1, 6 } };Â
        // Function Call        numWays(ratings, queries, N, K);    }} |
Python3
# Python3 program for the # above approachÂ
# Function to count number of# ways to get given sum groupsdef numWays(ratings, queries,             n, k):       # Initialise dp array    dp = [[0 for i in range(10002)]              for j in range(n)];Â
    # Mark all 1st row values as 1    # since the mat[0][i] is all    # possible sums in first row    for i in range(k):        dp[0][ratings[0][i]] += 1;Â
    # Fix the ith row    for i in range(1, n):Â
        # Fix the sum        for sum in range(10001):Â
            # Iterate through all            # values of ith row            for j in range(k):Â
                # If sum can be obtained                if (sum >= ratings[i][j]):                    dp[i][sum] += dp[i - 1][sum -                                            ratings[i][j]];Â
    # Find the prefix sum of    # last row    for sum in range(1, 10001):        dp[n - 1][sum] += dp[n - 1][sum - 1];Â
    # Traverse each query    for q in range(len(queries)):        a = queries[q][0];        b = queries[q][1];Â
        # No of ways to form groups        print(dp[n - 1][b] -              dp[n - 1][a - 1],               end = " ");Â
# Driver Codeif __name__ == '__main__':       # Given N batches and     # K students    N = 2;    K = 3;Â
    # Given ratings    ratings = [[1, 2, 3],                [4, 5, 6]];Â
    queries = [[6, 6],               [1, 6]];Â
    # Function Call    numWays(ratings, queries, N, K);Â
# This code is contributed by 29AjayKumar |
C#
// C# program for the above approachusing System;Â
class GFG{Â
// Function to count number of// ways to get given sum groupspublic static void numWays(int[,] ratings,                            int [,]queries,                            int n, int k){         // Initialise dp array    int [,]dp = new int[n, 10000 + 2];Â
    // Mark all 1st row values as 1    // since the mat[0,i] is all    // possible sums in first row    for(int i = 0; i < k; i++)        dp[0, ratings[0, i]] += 1;Â
    // Fix the ith row    for(int i = 1; i < n; i++)     {                 // Fix the sum        for(int sum = 0; sum <= 10000; sum++)         {                         // Iterate through all            // values of ith row            for(int j = 0; j < k; j++)             {Â
                // If sum can be obtained                if (sum >= ratings[i, j])                    dp[i, sum] += dp[i - 1,                                   sum - ratings[i, j]];            }        }    }Â
    // Find the prefix sum of last row    for(int sum = 1; sum <= 10000; sum++)    {        dp[n - 1, sum] += dp[n - 1, sum - 1];    }Â
    // Traverse each query    for(int q = 0; q < queries.GetLength(0); q++)    {        int a = queries[q, 0];        int b = queries[q, 1];Â
        // No of ways to form groups        Console.Write(dp[n - 1, b] -                       dp[n - 1, a - 1] + " ");    }}Â
// Driver Codepublic static void Main(String []args){         // Given N batches and K students    int N = 2, K = 3;Â
    // Given ratings    int [,]ratings = { { 1, 2, 3 }, { 4, 5, 6 } };Â
    // Given Queries    int [,]queries = { { 6, 6 }, { 1, 6 } };Â
    // Function Call    numWays(ratings, queries, N, K);}}Â
// This code is contributed by Amit Katiyar |
Javascript
<script>Â
// Javascript program for the above approachÂ
// Given n batches and k studentsvar n = 2;var k = 3;Â
// Function to count number of// ways to get given sum groupsfunction numWays(ratings, queries){         // Initialise dp array    var dp = Array.from(        Array(n), ()=>Array(10002).fill(0));Â
    // Mark all 1st row values as 1    // since the mat[0][i] is all    // possible sums in first row    for(var i = 0; i < k; i++)        dp[0][ratings[0][i]] += 1;Â
    // Fix the ith row    for(var i = 1; i < n; i++)     {                 // Fix the sum        for(var sum = 0; sum <= 10000; sum++)         {                         // Iterate through all            // values of ith row            for(var j = 0; j < k; j++)             {                                 // If sum can be obtained                if (sum >= ratings[i][j])                    dp[i][sum]+= dp[i - 1][sum - ratings[i][j]];            }        }    }Â
    // Find the prefix sum of last row    for(var sum = 1; sum <= 10000; sum++)     {        dp[n - 1][sum] += dp[n - 1][sum - 1];    }Â
    // Traverse each query    for(var q = 0; q < 2; q++)     {        var a = queries[q][0];        var b = queries[q][1];Â
        // No of ways to form groups        document.write(dp[n - 1][b] -                        dp[n - 1][a - 1] + " ");    }}Â
// Driver CodeÂ
// Given ratingsvar ratings = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ];Â
// Given Queriesvar queries = [ [ 6, 6 ], [ 1, 6 ] ];Â
// Function CallnumWays(ratings, queries);Â
// This code is contributed by famouslyÂ
</script> |
2 3
Time Complexity: O(N*maxSum*K), where maxSum is the maximum sum.
Auxiliary Space: O(N*maxSum), where maxSum is the maximum sum.
Efficient approach : Space optimization
In previous approach the dp[i][j] is depend upon the current and previous row of 2D matrix. So to optimize space we use two vectors curr and prev that keep track of current and previous row of DP.
Implementation Steps:
- Initialize two vectors curr and prev to keep track of only current and previous row of Dp with 0.
- Now iterative over subproblems and get the current computation.
- While iteration initialize curr vector.
- Now compute the current value by the help of prev vector and store that value in curr.
- After every iteration store values of curr vector in prev vector for further iteration.
- At last return the answer stored in curr[0].
Implementation:
C++
// C++ program for the above approachÂ
#include <bits/stdc++.h>using namespace std;Â
// Given n batches and k students#define n 2#define k 3Â
// Function to count number of// ways to get given sum groupsvoid numWays(int ratings[n][k], int queries[][2]){Â
    // Initialise dp array    // int dp[n][10000 + 2];    vector<int> prev(10000 + 2);    vector<int> curr(10000 + 2);Â
    // Mark all 1st row values as 1    // since the prev[i] is all    // possible sums in first row    for (int i = 0; i < k; i++)        prev[ratings[0][i]] += 1;Â
    // Fix the ith row    for (int i = 1; i < n; i++) {Â
        // Fix the sum        for (int sum = 0; sum <= 10000; sum++) {            // Iterate through all            // values of ith row            for (int j = 0; j < k; j++) {                // If sum can be obtained                if (sum >= ratings[i][j])                    curr[sum] += prev[sum - ratings[i][j]];            }        }Â
        // assigning values of curr vector to prev vector        // for further iteration        prev = curr;    }Â
    // Find the prefix sum of last row    for (int sum = 1; sum <= 10000; sum++) {        curr[sum] += curr[sum - 1];    }Â
    // Traverse each queryÂ
    for (int q = 0; q < 2; q++) {        int a = queries[q][0];        int b = queries[q][1];Â
        // No of ways to form groups        cout << curr[b] - curr[a - 1] << " ";    }}Â
// Driver Codeint main(){Â
    // Given ratings    int ratings[n][k] = { { 1, 2, 3 }, { 4, 5, 6 } };Â
    // Given Queries    int queries[][2] = { { 6, 6 }, { 1, 6 } };Â
    // Function Call    numWays(ratings, queries);Â
    return 0;} |
Javascript
// Given n batches and k studentsconst n = 2;const k = 3;Â
// Function to count number of ways to get given sum groupsfunction numWays(ratings, queries) {  // Initialize dp array  let prev = new Array(10000 + 2).fill(0);  let curr = new Array(10000 + 2).fill(0);Â
  // Mark all 1st row values as 1 since the prev[i] is all possible sums in first row  for (let i = 0; i < k; i++) prev[ratings[0][i]] += 1;Â
  // Fix the ith row  for (let i = 1; i < n; i++) {    // Fix the sum    for (let sum = 0; sum <= 10000; sum++) {      // Iterate through all values of ith row      for (let j = 0; j < k; j++) {        // If sum can be obtained        if (sum >= ratings[i][j]) curr[sum] += prev[sum - ratings[i][j]];      }    }Â
    // Assigning values of curr vector to prev vector for further iteration    prev = [...curr];  }Â
  // Find the prefix sum of last row  for (let sum = 1; sum <= 10000; sum++) {    curr[sum] += curr[sum - 1];  }Â
  // Traverse each query  for (let q = 0; q < queries.length; q++) {    let a = queries[q][0];    let b = queries[q][1];Â
    // No of ways to form groups    console.log(curr[b] - curr[a - 1]);  }}Â
// Given ratingsconst ratings = [  [1, 2, 3],  [4, 5, 6],];Â
// Given Queriesconst queries = [  [6,6],  [1,6]];Â
// Function CallnumWays(ratings, queries); |
Python3
# Python program for the above approachÂ
# Given n batches and k studentsn = 2k = 3Â
# Function to count number of# ways to get given sum groupsÂ
Â
def numWays(ratings, queries):Â
    # Initialise dp array    prev = [0] * (10000 + 2)    curr = [0] * (10000 + 2)Â
    # Mark all 1st row values as 1    # since the prev[i] is all    # possible sums in first row    for i in range(k):        prev[ratings[0][i]] += 1Â
    # Fix the ith row    for i in range(1, n):Â
        # Fix the sum        for s in range(0, 10001):Â
            # Iterate through all            # values of ith row            for j in range(k):Â
                # If sum can be obtained                if s >= ratings[i][j]:                    curr[s] += prev[s - ratings[i][j]]Â
        # assigning values of curr list to prev list        # for further iteration        prev = curr.copy()        curr = [0] * (10000 + 2)Â
    # Find the prefix sum of last row    for s in range(1, 10001):        prev[s] += prev[s - 1]Â
    # Traverse each query    for q in range(2):Â
        a = queries[q][0]        b = queries[q][1]Â
        # No of ways to form groups        print(prev[b] - prev[a - 1], end=' ')Â
Â
# Driver Codeif __name__ == '__main__':Â
    # Given ratings    ratings = [[1, 2, 3], [4, 5, 6]]Â
    # Given Queries    queries = [[6, 6], [1, 6]]Â
    # Function Call    numWays(ratings, queries) |
Output
2 3
Time Complexity: O(N*maxSum*K), where maxSum is the maximum sum.
Auxiliary Space: O(maxSum)
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!

… [Trackback]
[…] Read More here on that Topic: geeksforgeeks.org/queries-to-count-groups-of-n-students-possible-having-sum-of-ratings-within-given-range/ […]
… [Trackback]
[…] Find More on that Topic: geeksforgeeks.org/queries-to-count-groups-of-n-students-possible-having-sum-of-ratings-within-given-range/ […]