题目展示:
小 S 在学校积极响应全面发展的教育政策,精心挑选了 3 门必修课和 n 门选修课程。期末考核迫在眉睫,小 S 迫切地想弄清楚他所有课程的成绩究竟有多少种组合方式能够让他顺利及格。这里的及格标准是所有课程的平均分不得低于 60 分。要知道,每门课程的成绩是由 20 道选择题来决定的,每道题 5 分,答对就能得分,答错则一分不得。为了后续计算的便利性,最终结果需要对 202220222022 进行取模处理。
问题理解:
当我们第一眼看到这道题时,不难发现它需要我们去处理离散的数据。因为每门课程的成绩是由 20 道每题 5 分的选择题决定的,所以每门课程可能出现的成绩就只能是像 {0, 5, 10,…, 100} 这样的离散值。同时,由于题目要求计算有多少种组合方式能满足条件,假设存在四门课程,那么像{40,30,20,10}与{10,20,30,40}这样的组合其实相同的。所以,我们需要通过巧妙的组合计算,使得课程的成绩组合能够满足特定的条件,也就是平均分大于等于 60 分。对于这样的题目,很有可能需要我们去枚举所有可能的情况,或者运用动态规划的方法来解决。
课程成绩的特点:
每门课程的成绩都是由 20 道选择题决定的,每道题 5 分,答错不得分,答对才能得分。这就导致每门课程的成绩只能是 {0, 5, 10,…, 100} 这样的离散值。
平均分条件转换为总分条件:
及格的平均分大于等于 60 分,这等价于总分大于等于 60 乘以 (n + 3) 分。这里的 n + 3 是因为小 S 选择了 n 门选修课和 3 门必修课。
数据结构选择:
考虑到我们需要计算所有可能的组合方式,并且课程成绩是离散的,通过动态规划(DP)的方法能够高效地解决这个问题。
状态定义: 我们使用一维数组 dp[j] 来表示当前总分为 j 时的有效成绩组合数。
状态转移: 当当前课程的得分为 k 时,我们更新总分为 j 的状态:dp[j] 等于 dp[j - k] 的总和,其中 k 是从 0 到 100 的 5 的倍数,并且 j - k 大于等于 0 。
初始化: 我们将 dp[0] 初始化为 1,表示总分为 0 的组合数初始为 1 。
算法步骤:
-
初始化:
- 首先,我们将 n 加上 3(因为包含 3 门必修课)。
- 接着,初始化一个 DP 数组 old_dp,将 old_dp[0] 初始化为 1,表示当总分为 0 时,有 1 种组合方式。
-
动态规划:
- 依次遍历每一门课程(从第 1 门到第 n + 3 门)。
- 针对当前课程,初始化一个新的 DP 数组 new_dp,其大小为当前总分范围的最大值 100 × i。
- 对于当前课程,遍历可能的总分 j(从 0 到当前最大总分)。
- 同时,遍历当前课程可能的得分 k(从 0 到 100,每次增加 5 分)。如果 j - k 大于等于 0,那么 new_dp[j] 就等于 (new_dp[j] + old_dp[j - k])对 MOD 取模。
- 最后,用 new_dp 替换 old_dp,为下一门课程更新状态。
-
结果计算:
- 遍历总分范围(从 60 × (n + 3) 到 100 × (n + 3))。
- 将 ans 等于 (ans + new_dp[j])对 MOD 取模。
- 最终返回结果。