问题描述
小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'
解题思路
可使用动态规划来解决这个问题,定义一个二维数组 dp,其中 dp[i][j] 表示前 i 门课程总分为 j 的组合数。初始状态 dp[0][0] = 1,表示0门课程总分为0的组合数为1。然后,通过三重循环进行状态转移:外层循环遍历每一门课程 i,中间循环遍历所有可能的总分 j,内层循环遍历当前课程的所有可能分数 k(步长为5),更新 dp[i][j]。最后遍历所有满足平均分不低于60分的总分 j,累加 dp[totalCourses][j] 到 result,并对 MOD 取模,即可得到结果。
算法步骤
-
初始化:
- 首先,定义了一个常量
MOD,用于对结果取模。 - 计算总课程数
totalCourses,即n + 3。 - 计算最大可能的总分
maxScore,即100 * totalCourses。 - 初始化一个二维数组
dp,大小为(totalCourses + 1) * (maxScore + 1),初始值为0。 dp[0][0] = 1,表示0门课程总分为0的组合数为1。
- 首先,定义了一个常量
-
状态转移:
- 对于每一门课程
i(从1到totalCourses),遍历所有可能的总分j(从0到maxScore)。 - 对于每个总分
j,遍历所有可能的当前课程分数k(从0到100,步长为5),更新dp[i][j]。 - 具体更新方式为:
dp[i][j] = (dp[i][j] + dp[i - 1][j - k]) % MOD,表示当前课程得分为k时,前i-1门课程总分为j-k的组合数。
- 对于每一门课程
-
结果计算:
- 计算所有满足平均分不低于60分的组合数。
- 遍历所有可能的总分
j(从60 * totalCourses到maxScore,步长为5),累加dp[totalCourses][j]到result。 - 最终结果对
MOD取模,并返回结果。
代码实现
public class Main {
public static String solution(int n) {
long MOD = 202220222022L;
int totalCourses = n + 3;
int maxScore = 100 * totalCourses;
// 初始化dp数组
long[][] dp = new long[totalCourses + 1][maxScore + 1];
dp[0][0] = 1;
// 状态转移
for (int i = 1; i <= totalCourses; i++) {
for (int j = 0; j <= maxScore; j+=5) {
for (int k = 0; k <= 100; k = k + 5) {
if (j >= k) {
dp[i][j] = (dp[i][j] + dp[i - 1][j - k]) % MOD;
}
}
}
}
// 计算结果
long result = 0;
for (int j = 60 * totalCourses; j <= maxScore; j = j + 5) {
result = (result + dp[totalCourses][j]) % MOD;
}
return String.valueOf(result);
}
}