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

📅  最后修改于: 2021-09-17 07:34:53             🧑  作者: Mango

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

例子:

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

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

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

  • 初始化辅助阵列DP [] [],其中DP [I] [总和]是一个总和是存在于第i中的次数。
  • 对于每个批次,遍历所有可能的总和S ,对于每个j 个学生,如果总和S大于当前评分ratings[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


Javascript


输出
2 3 

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

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程