【笔试题汇总】美团笔试题题解 第四场 2024.3.30

这里是paoxiaomo,一个现役ACMer,之后将会持续更新算法笔记系列以及笔试题题解系列
本文章面向想打ICPC/蓝桥杯/天梯赛等程序设计竞赛,以及各个大厂笔试的选手
感谢大家的订阅➕ 和 喜欢💗
有什么想看的算法专题可以私信博主

(本文题面由清隆学长收集)

01.K小姐的旅行预算计划

题目描述

K小姐计划去欧洲旅行,她的旅行预算总额为 k k k 欧元。旅行期间,她打算在交通、住宿和餐饮三个方面进行开销。经过仔细规划,K小姐发现,住宿的花费比交通多 x x x 欧元,而比餐饮少 y y y 欧元。请你帮助 K小姐计算出交通、住宿和餐饮三个方面各自的开销金额。

输入格式

输入包含一行,包含三个整数 k k k, x x x, y y y,分别表示旅行预算总额,住宿比交通多的金额,以及住宿比餐饮少的金额。其中, 1 ≤ k ≤ 10000 1 \le k \le 10000 1k10000 − 1000 ≤ x , y ≤ 1000 -1000 \le x, y \le 1000 1000x,y1000。保证输入数据合法,即算出的三个开销金额均为正整数。

输出格式

输出一行,包含三个正整数,分别表示 K小姐在交通、住宿和餐饮三个方面各自的开销金额。

样例输入

5000 200 300

样例输出

1500 1700 2000

数据范围

  • 1 ≤ k ≤ 10000 1 \le k \le 10000 1k10000
  • − 1000 ≤ x , y ≤ 1000 -1000 \le x, y \le 1000 1000x,y1000

【题目解析】

这道题目需要根据给定的旅行预算总额 k k k,以及住宿比交通多的金额 x x x 和住宿比餐饮少的金额 y y y,计算出在交通、住宿和餐饮三个方面的开销金额。

设交通开销为 t t t,住宿开销为 a a a,餐饮开销为 b b b

根据题目描述可得以下等式:

  1. a = t + x a = t + x a=t+x
  2. a = b − y a = b - y a=by
  3. t + a + b = k t + a + b = k t+a+b=k

将等式1和等式2代入等式3,解得 t t t a a a b b b 的值。

cpp

#include <iostream>

using namespace std;

int main() {
    int k, x, y;
    cin >> k >> x >> y;

    // 计算交通、住宿和餐饮三个方面的开销金额
    int t = (k - y) * 2 / 5; // 交通开销
    int a = t + x;           // 住宿开销
    int b = a - y;           // 餐饮开销

    // 输出结果
    cout << t << " " << a << " " << b << endl;

    return 0;
}

02.LYA 的旅行景点打分

题目描述

LYA 计划去 n n n 个旅行景点游玩,她对每个景点都有一个初始打分 a i a_i ai。在旅行过程中,如果某个景点给她留下了非常深刻的印象,她就会将该景点的打分加倍。LYA 想知道,如果她在每个景点都将打分加倍,那么最终她给所有景点的最高分是多少。请你帮她计算出每次加倍后的最高分。

输入格式

第一行输入一个正整数 n n n,代表旅行景点的数量。

第二行输入 n n n 个正整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an,代表 LYA 对每个景点的初始打分。

输出格式

输出 n n n 个正整数,用空格隔开,依次代表 LYA 在每个景点将打分加倍后,当前的最高分。

样例输入

5
1 3 2 5 4

样例输出

5 6 5 10 8

数据范围

  • 1 ≤ n ≤ 2 × 1 0 5 1 \le n \le 2 \times 10^5 1n2×105
  • 1 ≤ a i ≤ 1 0 9 1 \le a_i \le 10^9 1ai109

【题目解析】

解题思路

可以通过遍历每个景点,将每个打分都加倍,并记录下最大值。

cpp

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main() {
    int n;
    cin >> n;

    vector<int> ratings(n);

    // 读取每个景点的初始打分
    for (int i = 0; i < n; ++i) {
        cin >> ratings[i];
    }

    // 找出每次加倍后的最高分
    int max_rating = 0;
    for (int i = 0; i < n; ++i) {
        max_rating = max(max_rating, ratings[i] * 2);
    }

    // 输出每次加倍后的最高分
    for (int i = 0; i < n; ++i) {
        cout << max_rating << " ";
    }
    cout << endl;

    return 0;
}

03.LYA 的字符串修改计划

题目描述

LYA 有两个长度相等的字符串 s s s t t t,她希望通过一系列操作使得这两个字符串相等。每次操作,LYA 可以选择一个字符串的一个前缀,然后选择一个字母 c c c,将选择的前缀的所有字母都替换成字母 c c c。LYA 想知道最少需要多少次操作才能使得字符串 s s s t t t 相等,并希望你能给出具体的操作方案。

输入格式

第一行输入一个长度不超过 1 0 5 10^5 105 的字符串 s s s

第二行输入一个长度与 s s s 相等的字符串 t t t

输出格式

第一行输出一个整数 m m m,表示最少操作次数。

接下来 m m m 行,每行输出用空格隔开的三个参数 i i i, j j j, c c c,表示对第 i i i 个字符串的长度为 j j j 的前缀进行替换,将前缀所有字母替换成字母 c c c

样例输入

aabc
abcc

样例输出

2
2 3 b
2 2 a

数据范围

  • 字符串 s s s t t t 的长度不超过 1 0 5 10^5 105

【题目解析】

可以通过遍历字符串的每个位置,比较对应位置的字母,找出需要操作的位置及替换的字母。首先读取输入的两个长度相等的字符串 s s s t t t。然后遍历两个字符串的每个位置,比较对应位置的字母,如果不相等则记录需要操作的位置及替换的字母。最后输出操作次数和具体操作方案,即需要操作的位置及替换的字母。

cpp

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main() {
    string s, t;
    cin >> s >> t;

    int n = s.size();
    vector<pair<int, char>> operations;

    // 找出需要操作的位置及替换的字母
    for (int i = 0; i < n; ++i) {
        if (s[i] != t[i]) {
            operations.push_back({i + 1, t[i]});
        }
    }

    // 输出操作次数和具体操作方案
    int m = operations.size();
    cout << m << endl;
    for (int i = 0; i < m; ++i) {
        cout << operations[i].first << " " << 1 << " " << operations[i].second << endl;
    }

    return 0;
}

04.平衡串的数量

题目描述

LYA 非常喜欢研究字符串。最近她定义了一种平衡串:

  • 平衡串必须仅包含两种字符,且这两种字符出现的次数相等。

例如 ababba 就是一个平衡串。

现在,LYA 有一个长度为 n n n 的字符串 s s s,她想知道 s s s 有多少个子序列是平衡串。这里的子序列是指从 s s s 中选取若干个字符(可以不连续)按照原来的顺序组成的字符串。

例如,acaarcaea 的一个子序列。

输入格式

第一行包含一个正整数 n n n,表示字符串的长度。

第二行包含一个长度为 n n n 的字符串 s s s,仅由小写字母组成。

输出格式

输出一个整数,表示字符串 s s s 中平衡串子序列的个数。

答案可能很大,请将答案对 1 0 9 + 7 10^9+7 109+7 取模后输出。

样例输入

5
ababc

样例输出

9

数据范围

1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1n2×105

【题目解析】

解题思路

为了解决这个问题,可以使用动态规划。我们可以定义一个二维数组 dp[i][j],表示从字符串的第一个字符到第 i 个字符中,以字符 j 结尾的子序列中平衡串的数量。然后我们可以按照字符串的顺序逐个字符地计算 dp[i][j] 的值。

具体步骤如下:

  1. 初始化二维数组 dp,令 dp[0][j] = 0,其中 j 表示字符的 ASCII 值,dp[1][s[0]] = 1
  2. 遍历字符串中的每个字符,对于当前字符 s[i]
    • 如果 s[i] 之前没有出现过,那么 dp[i+1][s[i]] = 1,并且对于所有 k != s[i]dp[i+1][k] = dp[i][k]
    • 如果 s[i] 之前出现过,则 dp[i+1][s[i]] 的值需要加上所有 dp[j][s[i]] 的值,其中 j 表示字符 s[i] 上一次出现的位置。
  3. 最终答案为所有 dp[n][j] 的和,其中 j 表示字符串中出现的字符。

cpp

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>

using namespace std;

const int MOD = 1000000007;

int main() {
    int n;
    cin >> n;
    string s;
    cin >> s;

    vector<vector<int>> dp(n + 1, vector<int>(26, 0));
    unordered_map<char, int> last_pos;

    for (int i = 0; i < n; ++i) {
        char ch = s[i];
        dp[i + 1] = dp[i];
        dp[i + 1][ch - 'a'] = (dp[i + 1][ch - 'a'] + 1) % MOD;
        if (last_pos.find(ch) != last_pos.end()) {
            for (int j = 0; j < 26; ++j) {
                if (j != ch - 'a') {
                    dp[i + 1][j] = (dp[i + 1][j] + dp[last_pos[ch]][j]) % MOD;
                }
            }
        }
        last_pos[ch] = i + 1;
    }

    int result = 0;
    for (int j = 0; j < 26; ++j) {
        result = (result + dp[n][j]) % MOD;
    }

    cout << result << endl;

    return 0;
}

05.K小姐的生日派对

问题描述

K小姐要过生日了,她准备邀请一些朋友来参加生日派对。但是,在她的朋友圈子里,有一些人之间存在着暗恋关系。如果一个人暗恋另一个人,那么只有在他暗恋的人也被邀请的情况下,他才会愿意参加派对。

现在给定 n n n 个人和 m m m 对暗恋关系,请你帮 K小姐 计算一下,一共有多少种邀请朋友的方案可以让所有被邀请的人都愿意参加派对。由于答案可能很大,请对 1 0 9 + 7 10^9+7 109+7 取模。

输入格式

第一行包含两个正整数 n n n m m m,分别表示人数和暗恋关系数。

接下来 m m m 行,每行包含两个正整数 u u u v v v,表示编号为 u u u 的人暗恋编号为 v v v 的人。

输出格式

输出一个整数,表示邀请朋友的方案数对 1 0 9 + 7 10^9+7 109+7 取模后的结果。

样例输入


3 3
1 2
2 3
3 1

样例输出


1

数据范围

  • 1 ≤ n , m ≤ 1 0 5 1 \leq n, m \leq 10^5 1n,m105
  • 1 ≤ u , v ≤ n 1 \leq u, v \leq n 1u,vn
  • 保证每个人最多只会暗恋一个人

【题目解析】

这道题目可以通过图论中的拓扑排序来解决。首先,根据暗恋关系构建有向图,然后对该有向图进行拓扑排序。拓扑排序的结果表示了一种满足暗恋关系的邀请顺序。

具体步骤如下:

  1. 构建有向图:根据给定的暗恋关系,构建有向图,图中每个节点表示一个人,每个边表示一个人暗恋另一个人。
  2. 拓扑排序:对构建好的有向图进行拓扑排序,得到一个满足暗恋关系的邀请顺序。
  3. 计算方案数:根据拓扑排序结果,计算出满足条件的邀请方案数。

cpp

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

const int MOD = 1000000007;

int main() {
    int n, m;
    cin >> n >> m;

    vector<vector<int>> graph(n + 1);
    vector<int> indegree(n + 1, 0);

    // 构建有向图
    for (int i = 0; i < m; ++i) {
        int u, v;
        cin >> u >> v;
        graph[u].push_back(v);
        indegree[v]++;
    }

    // 拓扑排序
    queue<int> q;
    for (int i = 1; i <= n; ++i) {
        if (indegree[i] == 0) {
            q.push(i);
        }
    }

    long long ways = 1;
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        for (int v : graph[u]) {
            indegree[v]--;
            if (indegree[v] == 0) {
                q.push(v);
                ways = (ways * 2) % MOD; // 对于每个节点,可以选择邀请或不邀请,所以乘以2
            }
        }
    }

    cout << ways << endl;

    return 0;
}

这段 C++ 代码实现了上述思路。首先构建有向图,然后进行拓扑排序,并在拓扑排序的过程中计算满足条件的邀请方案数。最后将方案数对 1 0 9 + 7 10^9+7 109+7 取模后输出。
整理试题不易,你的关注是我更新的最大动力!关注博主 带你看更多面试及竞赛试题和实用算法。

  • 32
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值