AI刷题-及格的组合方式探索、英雄决斗的最大胜利次数

目录

一、及格的组合方式探索

问题描述

测试样例

解题思路: 

问题理解

关键点

数据结构与算法选择

算法步骤

最终代码:

运行结果: 

二、 英雄决斗的最大胜利次数

问题描述

标准输入

标准输出

解题思路:

问题理解

数据结构选择

算法步骤

最终代码: 

运行结果: 


一、及格的组合方式探索

问题描述

小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取模。

关键点

  1. 平均分不低于60分:这意味着所有课程的总分至少为 (3 + n) * 60 分。
  2. 每门课的成绩范围:每门课的成绩可以是0到100分之间的任意整数。
  3. 组合方式的计算:我们需要计算所有可能的组合方式,使得总分满足条件。

数据结构与算法选择

  1. 动态规划:可以考虑使用动态规划来解决这个问题。我们可以定义一个状态 dp[i][j] 表示前 i 门课总分为 j 的组合数。
  2. 状态转移:对于每一门课,我们可以从0到100分进行遍历,更新状态 dp[i][j]

算法步骤

  1. 初始化dp[0][0] = 1,表示0门课总分为0的组合数为1。
  2. 状态转移:对于每一门课 i,遍历所有可能的分数 k(从0到100),更新 dp[i][j]
  3. 结果计算:最终结果是所有满足总分条件的组合数之和,并对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 轮比赛中获胜的次数最多。

数据结构选择

  1. 小 W 的英雄能力值数组:由于小 W 的出场顺序是固定的,我们可以直接使用输入的数组来表示小 W 的英雄能力值。
  2. 小 Y 的英雄能力值数组:小 Y 的英雄能力值数组需要进行排序,以便在每轮比赛中选择最优的英雄来对抗小 W 的英雄。

算法步骤

  1. 排序:首先对小 Y 的英雄能力值数组进行排序,以便我们可以从中选择最优的英雄。
  2. 双指针法:使用两个指针,一个指向小 W 的英雄能力值数组(从前往后),另一个指向小 Y 的英雄能力值数组(从后往前)。
  3. 比较与计数:在每轮比赛中,比较小 W 和小 Y 当前指针所指的英雄能力值:
    • 如果小 Y 的英雄能力值大于小 W 的英雄能力值,则小 Y 获胜,计数器加一,两个指针都向前移动。
    • 如果小 Y 的英雄能力值小于或等于小 W 的英雄能力值,则小 Y 的英雄指针向前移动,寻找下一个更强的英雄。
  4. 返回结果:最终返回计数器的值,即小 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;
}

运行结果: 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

像污秽一样

谢谢谢谢谢谢谢谢谢谢谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值