给定整数N和K分别代表批次数量和每批次中的学生数量,以及大小为N * K的2D数组rating [] [] ,其中每一行都有每K个学生的评分,并且Q查询类型为{a, b} 。每个查询的任务是通过从每批中选择一个学生来计数N个学生的可能组数,以使每个组中的评分总和位于[a,b]范围内。
例子:
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.
天真的方法:最简单的方法是使用递归来生成大小为N的所有可能的组。在递归的每个步骤中,计算位于查询范围内的总和,并找到位于给定范围内的组数。
时间复杂度: O(N K )
辅助空间: O(1)
高效的方法:可以通过使用动态规划来优化上述方法。我们的想法是,如果次数总和在I S出现第i行是已知的,那么前缀和技术可以用来回答在固定时间内的所有查询。因此,以这种方式,仅在将指数时间减少为多项式时间后才计算重叠子问题。步骤如下:
- 初始化辅助阵列DP [] [],其中DP [I] [总和]是一个总和是存在于第i行中的次数。
- 对于每个批次,我将遍历所有可能的总和S ,对于每个j个学生,如果总和S大于当前等级rating [i] [j] ,则将当前dp状态dp [i] [S]更新为:
dp[i][S] = dp[i][S] + dp[i – 1][sum – rating[i][j]]
- 在上述步骤之后,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是最大和。