中等题 及格的组合方式探索 | 豆包MarsCode AI刷题

178 阅读4分钟

及格的组合方式探索

问题描述

问题描述

小S在学校选择了3门必修课和n门选修课程来响应全面发展的教育政策。现在期末考核即将到来,小S想知道他所有课程的成绩有多少种组合方式能使他及格。及格的条件是所有课程的平均分不低于60分。每门课程的成绩是由20道选择题决定,每题5分,答对得分,答错不得分。为了计算方便,你需要将结果对202220222022取模。

测试样例

样例1:

输入:n = 3
输出:'19195617'

样例2:

输入:n = 6
输出:'135464411082'

样例3:

输入:n = 49
输出:'174899025576'

样例4:

输入:n = 201
输出:'34269227409'

样例5:

输入:n = 888
输出:'194187156114'

解题思路

在解决这种成绩组合问题时,初步想到的可能是使用递归方法,不断遍历每一种得分组合。递归的思想简单明了,每一门课程逐步累加分数,直到计算出所有课程的总分。然而,随着课程数量 ( n ) 的增大,递归的深度也会急剧增加,导致计算复杂度成倍提升。最终,这种递归方法往往会因为递归深度过高而导致栈溢出,或者因庞大的计算量而引发时间超时问题。

即使尝试使用记忆化(备忘录)来优化递归,以减少重复计算,效果也非常有限。记忆化只能在一定程度上避免重复计算,但对于大规模问题而言,递归的固有劣势仍然存在,难以根本性地解决时间和空间上的挑战。

为了解决这个问题,动态规划(DP)是一种更为高效的方案。动态规划通过建立一个状态转移表,分阶段存储每一门课程分数的所有组合情况,避免了深度递归带来的开销。相比递归,动态规划通过自底向上的方式逐步求解,能够有效控制时间复杂度,并且没有栈溢出的问题。

  • 初始化:首先计算一门课程的所有得分组合。对于 dp[1][i],其中 i 是0到100的5的倍数,初始化为 1,表示每种单门课程得分的组合方式。

  • 状态转移

    • 从第二门课程开始迭代至第 n+3 门课程(共 n+3 门课程)。
    • 对于每门课程总得分 j,在前一门课程的所有可能分数基础上迭代(从0到100,每次步进5)。
    • 如果 j >= k,则 dp[i][j] += dp[i-1][j-k] 表示第 i 门课程总得分 j 的组合数等于第 i-1 门课程的所有符合条件的组合数之和。
    • 每次累加时对结果取模,以防止数值过大。
  • 结果累加

    • 由于平均分不低于60分的条件,所有课程总分应不小于 60 * (n+3)
    • 遍历 dp[courseNumber][sumScore],即 dp[n+3][sumScore],将符合条件的 sumScore 值累加,得到满足条件的所有组合数。

代码

public class Main {
    private static final long MOD = 202220222022L;

    public static String solution(int n) {
        int courseNumber = n + 3;
        long[][] dp = new long[courseNumber+1][courseNumber * 100+1];
        for(int i = 0; i <= 100; i+=5){
            dp[1][i] = 1;
        }
        for(int i = 2; i <= courseNumber; i++){
            for(int j = 0; j <= courseNumber * 100; j+=5){
                for(int k = 0; k <= 100; k+=5){
                    if(j >= k){
                        dp[i][j] += dp[i-1][j - k];
                        dp[i][j] %= MOD;
                    }
                }
            }
        }
        long result = 0;
        for (int sumScore = 60 * courseNumber; sumScore <= courseNumber * 100; sumScore+=5) {
            result += dp[courseNumber][sumScore];
            result %= MOD;  // 取模
        }
        
        return Long.toString(result);
    }
 

    public static void main(String[] args) {
        // You can add more test cases here
        System.out.println(solution(3).equals("19195617"));
        System.out.println(solution(6).equals("135464411082"));
        System.out.println(solution(49).equals("174899025576"));
        System.out.println(solution(201).equals("34269227409"));
        System.out.println(solution(888).equals("194187156114"));
    }
}