📌  相关文章
📜  对N个学生的组进行计数的查询,这些组的评分总和可能在给定范围内

📅  最后修改于: 2021-04-24 20:43:50             🧑  作者: Mango

给定整数NK分别代表批次数量和每批次中的学生数量,以及大小为N * K的2D数组rating [] [] ,其中每一行都有每K个学生的评分,并且Q查询类型为{a, b} 。每个查询的任务是通过从每批中选择一个学生来计数N个学生的可能组数,以使每个组中的评分总和位于[a,b]范围内。

例子:

天真的方法:最简单的方法是使用递归来生成大小为N的所有可能的组。在递归的每个步骤中,计算位于查询范围内的总和,并找到位于给定范围内的组数

时间复杂度: O(N K )
辅助空间: O(1)

高效的方法:可以通过使用动态规划来优化上述方法。我们的想法是,如果次数总和I S出现第i行是已知的,那么前缀和技术可以用来回答在固定时间内的所有查询。因此,以这种方式,仅在将指数时间减少为多项式时间后才计算重叠子问题。步骤如下:

  • 初始化辅助阵列DP [] [],其中DP [I] [总和]是一个总和是存在于第i中的次数。
  • 对于每个批次,我将遍历所有可能的总和S ,对于每个j个学生,如果总和S大于当前等级rating [i] [j] ,则将当前dp状态dp [i] [S]更新为:
  • 在上述步骤之后,DP [N – 1] [总和],它是和出现在(N – 1)的次数第i
  • 为了有效地回答每个查询,请找到最后一行的前缀和,即总和S的所有值的dp [N – 1] [S]
  • 现在,在给定范围[a,b]中形成组的方式为dp [N – 1] [b] – dp [N – 1] [a – 1]

下面是上述方法的实现:

C++
// C++ program for the above approach
 
#include 
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 groups
void 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 Code
int 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 groups
def 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 Code
if __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 approach
using System;
 
class GFG{
 
// 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.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 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);
}
}
 
// This code is contributed by Amit Katiyar


输出
2 3 




时间复杂度: O(N * maxSum * K),其中maxSum是最大总和。
辅助空间: O(N * maxSum),其中maxSum是最大和。