中等:及格的组合方式 题目:### 问题描述
小S在学校选择了3门必修课和n门选修课程来响应全面发展的教育政策。现在期末考核即将到来,小S想知道他所有课程的成绩有多少种组合方式能使他及格。及格的条件是所有课程的平均分不低于60分。每门课程的成绩是由20道选择题决定,每题5分,答对得分,答错不得分。为了计算方便,你需要将结果对202220222022取模。
ai帮助理解题意概括大意如下
小S选了3门必修课和 nnn 门选修课,每门课通过20道选择题(每题5分)评分,满分为100分。为了及格,所有课程的平均分必须不低于60分。
题目要求计算所有可能的成绩组合,使得平均分不低于60分,并对结果取模 202220222022202220222022202220222022。
输入输出
- 输入:一个整数 nnn,表示选修课的数量。
- 输出:符合条件的成绩组合数,对 202220222022202220222022202220222022 取模
随后ai给出解题思路: 通过动态规划解决,动态规划的主要设计思路:使用二维动态规划数组dp[i][j]其中dp[i][j]表示前前i门课可以获得总分为j的组合数。 转移方程:对于每门客的成绩从0-20进行遍历,根据前一个来更新。 经过思考得出答案
import java.math.BigInteger;
public class Main {
public static String solution(int n) {
// 模数
final long MOD = 202220222022L;
// dp数组
long[][] dp = new long[n + 4][20 * (n + 3) + 1];
// 初始化dp
dp[0][0] = 1;
// 动态规划填表
for (int i = 1; i <= n + 3; i++) {
for (int j = 0; j <= 20 * (n + 3); j++) {
for (int k = 0; k <= 20; k++) {
if (j >= k) {
dp[i][j] = (dp[i][j] + dp[i - 1][j - k]) % MOD;
}
}
}
}
// 计算满足条件的组合数
long count = 0;
for (int j = 12 * (n + 3); j <= 20 * (n + 3); j++) {
count = (count + dp[n + 3][j]) % MOD;
}
return Long.toString(count);
}
public static void main(String[] args) {
// 测试用例
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"));
}
}
最后就是ai总结做题思路以及方法
这道题是一个典型的动态规划问题,涉及到选修课程的组合数计算。目标是求出所有课程的成绩组合数,使得平均分不低于60分,并对结果取模 202220222022202220222022202220222022。具体思路如下:
-
课程分数的范围:
- 每门课程有20道题,每题5分,所以每门课的成绩可能为 0 到 100 分之间的整数,且分数为 5 的倍数。
- 小S总共有 3+n3 + n3+n 门课程,因此总成绩的范围为 000 到 20×(3+n)20 \times (3 + n)20×(3+n)。
-
及格条件:
- 平均分不低于60分,意味着所有课程的总分要达到 60×(3+n)=12×(3+n)60 \times (3 + n) = 12 \times (3 + n) 60×(3+n)=12×(3+n) 分。因此,只需要统计总成绩大于或等于 12×(3+n)12 \times (3 + n)12×(3+n) 的组合数。
-
动态规划设计:
- 使用二维动态规划数组
dp[i][j],其中dp[i][j]表示使用前i门课可以得到总分为j的组合数。 - 转移方程:对于每门课的成绩从
0到20进行遍历,将dp[i][j]更新为dp[i-1][j-k]的累加和,这样就可以在加入第i门课的基础上更新总分j的组合数。
- 使用二维动态规划数组
-
初始化:
- 初始化
dp[0][0] = 1,即在选择0门课程且总成绩为0的情况下有1种组合。
- 初始化
-
组合数的求和:
- 通过遍历
dp[n+3][j](即所有3 + n门课程的组合)找到满足j >= 12 \times (3 + n)的所有组合数,求和得到符合条件的组合数。
- 通过遍历
-
模运算:
- 因为组合数可能非常大,所以每次累加时对 202220222022202220222022202220222022 取模,避免整数溢出。
代码分析
-
MOD 值定义:使用
MOD = 202220222022来处理大数取模问题。 -
dp 数组初始化:
dp的大小是n + 4行,20 * (n + 3) + 1列。n+4是为了包含3门必修课和n门选修课的总课程数。 -
三重循环填表:
- 外层循环遍历课程数
i。 - 中间循环遍历总分
j。 - 内层循环遍历当前课程的可能分数
k(从 0 到 20)。
- 外层循环遍历课程数
-
结果计算:遍历
dp[n + 3][j],统计满足条件的组合数。
优化技巧
- 模数限制:每次累加时都取模
MOD,以防止整数溢出。 - 动态规划:利用前一行的结果来计算当前行的值,大大减少了重复计算的情况。
- 剪枝:内层循环中如果
j < k,直接跳过计算,减少不必要的更新操作。
复杂度分析
- 时间复杂度:三重循环的时间复杂度约为 O((n+3)×(20×(n+3))×20)O((n + 3) \times (20 \times (n + 3)) \times 20)O((n+3)×(20×(n+3))×20),整体复杂度较高。
- 空间复杂度:使用了一个二维数组
dp,大小为 O((n+3)×20×(n+3))O((n + 3) \times 20 \times (n + 3))O((n+3)×20×(n+3))。