给定整数N和K,分别代表批次数和每批学生人数,以及大小为N * K的二维数组ratings[][] ,其中每行都有每K 个学生的评分和Q类型的查询{a,乙} 。每个查询的任务是通过从每个批次中选择一个学生来计算可能的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大于当前评分ratings[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
Javascript
2 3
时间复杂度: O(N*maxSum*K),其中 maxSum 是最大和。
辅助空间: O(N*maxSum),其中 maxSum 是最大和。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。