目录
一、及格的组合方式探索
问题描述
小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'
解题思路:
问题理解
小S有3门必修课和n
门选修课,每门课的成绩由20道选择题决定,每题5分,总分100分。我们需要计算所有课程成绩的组合方式,使得所有课程的平均分不低于60分。最终结果需要对202220222022取模。
关键点
- 平均分不低于60分:这意味着所有课程的总分至少为
(3 + n) * 60
分。 - 每门课的成绩范围:每门课的成绩可以是0到100分之间的任意整数。
- 组合方式的计算:我们需要计算所有可能的组合方式,使得总分满足条件。
数据结构与算法选择
- 动态规划:可以考虑使用动态规划来解决这个问题。我们可以定义一个状态
dp[i][j]
表示前i
门课总分为j
的组合数。 - 状态转移:对于每一门课,我们可以从0到100分进行遍历,更新状态
dp[i][j]
。
算法步骤
- 初始化:
dp[0][0] = 1
,表示0门课总分为0的组合数为1。 - 状态转移:对于每一门课
i
,遍历所有可能的分数k
(从0到100),更新dp[i][j]
。 - 结果计算:最终结果是所有满足总分条件的组合数之和,并对202220222022取模。
最终代码:
#include <iostream>
#include <vector>
using namespace std;
const long long MOD = 202220222022;
string solution(int n) {
n += 3; // 因为有3门必修,贼坑
vector<long long> old_dp(101, 0); // 动态规划优化空间,2个一维dp即可
old_dp[0] = 1;
vector<long long> new_dp;
for (int i = 1; i <= n; ++i) {
int MaxScore = 100 * i;
new_dp.assign(MaxScore + 1, 0);
for (int j = 0; j <= MaxScore; j += 5) {
for (int k = 0; k <= 100; k += 5) {
if (j - k <= (i - 1) * 100 && j - k >= 0) {
if (old_dp[j - k] > 0)
new_dp[j] = (new_dp[j] + old_dp[j - k]) % MOD;
} else if (j - k < 0) {
break;
}
}
}
old_dp = new_dp;
}
long long ans = 0;
for (int i = 60 * n; i <= 100 * n; i += 5) {
ans = (new_dp[i] + ans) % MOD;
}
return to_string(ans);
}
int main() {
// You can add more test cases here
cout << (solution(3) == "19195617") << endl;
cout << (solution(6) == "135464411082") << endl;
cout << (solution(49) == "174899025576") << endl;
cout << (solution(201) == "34269227409") << endl;
cout << (solution(888) == "194187156114") << endl;
return 0;
}
运行结果:
怎么变洋文了
二、 英雄决斗的最大胜利次数
问题描述
小 W 和小 Y 在玩一个游戏,他们分别有 n 个英雄,能力值为 ai(1 <= i <= n),他们接下来会进行 n 轮比赛,每轮比赛小 W 和小 Y 都从各自的英雄中挑选 1 名进行决斗,能力值高者方胜利,每名英雄只能出场一次。由于小 W 比较自信,出场顺序固定成从 1,2,... 到 n,于是小 Y 想知道,怎么安排出场顺序使得获胜次数最高?
标准输入
第一行输入 1 个正整数 n(1 <= n <= 100000),表示英雄数量
第二行输入 n 个正整数 a1, a2,..., an,(1 <= ai <= 1e9) 分别表示各自英雄的能力值
标准输出
一行答案,小 Y 最优上场策略下的获胜次数
样例输入 1
7
10 1 1 1 5 5 3
样例输出 1
4
样例解释
小 Y 安排上场顺序为 (1 3 5 5 10 1 1),能够保证第 2,3,4,5 场决斗胜利,所以答案为 4
样例输入 2
5
1 1 1 1 1
样例输出 2
0
解题思路:
问题理解
小 W 和小 Y 各有 n 个英雄,每个英雄有一个能力值。小 W 的出场顺序是固定的,从 1 到 n。小 Y 需要安排他的英雄出场顺序,使得在 n 轮比赛中获胜的次数最多。
数据结构选择
- 小 W 的英雄能力值数组:由于小 W 的出场顺序是固定的,我们可以直接使用输入的数组来表示小 W 的英雄能力值。
- 小 Y 的英雄能力值数组:小 Y 的英雄能力值数组需要进行排序,以便在每轮比赛中选择最优的英雄来对抗小 W 的英雄。
算法步骤
- 排序:首先对小 Y 的英雄能力值数组进行排序,以便我们可以从中选择最优的英雄。
- 双指针法:使用两个指针,一个指向小 W 的英雄能力值数组(从前往后),另一个指向小 Y 的英雄能力值数组(从后往前)。
- 比较与计数:在每轮比赛中,比较小 W 和小 Y 当前指针所指的英雄能力值:
- 如果小 Y 的英雄能力值大于小 W 的英雄能力值,则小 Y 获胜,计数器加一,两个指针都向前移动。
- 如果小 Y 的英雄能力值小于或等于小 W 的英雄能力值,则小 Y 的英雄指针向前移动,寻找下一个更强的英雄。
- 返回结果:最终返回计数器的值,即小 Y 获胜的次数。
最终代码:
#include <iostream>
#include <vector>
#include <algorithm> // 用于排序
int solution(int number, std::vector<int> heroes) {
// 小 W 的英雄队伍固定为 1 到 n
std::vector<int> u_heroes(number);
for (int i = 0; i < number; ++i) {
u_heroes[i] = i + 1;
}
// 小 F 的英雄队伍排序
std::sort(heroes.begin(), heroes.end());
// 双指针初始化
int u_pointer = 0;
int f_pointer = 0;
int victories = 0;
// 双指针遍历
while (f_pointer < number && u_pointer < number) {
// 如果小 Y 的英雄能力值大于小 W 的英雄能力值
if (heroes[f_pointer] > u_heroes[u_pointer]) {
victories += 1; // 小 F 获胜
u_pointer += 1; // 移动小 U 的指针
f_pointer += 1; // 移动小 F 的指针
} else {
// 否则小 Y 的英雄输掉了,尝试下一位小 Y 的英雄
f_pointer += 1;
}
}
return victories;
}
int main() {
// 你可以添加更多测试用例
std::vector<int> heroes1 = {10, 1, 1, 1, 5, 5, 3};
std::vector<int> heroes2 = {1, 1, 1, 1, 1};
std::vector<int> heroes3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::cout << (solution(7, heroes1) == 4) << std::endl;
std::cout << (solution(5, heroes2) == 0) << std::endl;
std::cout << (solution(10, heroes3) == 9) << std::endl;
return 0;
}
运行结果: