2024年第十五届蓝桥省赛中级组C++真题(附解析)
一、选择题(选择题严禁使用程序验证,选择题不答或答错都不扣分)
1、定义 char a[]="hello\nworld",执行 cout<<a,输出结果是( )
A、helloworld
B、 hello
world
C、hellonworld
D、hello\nworld
解析:\n输出时会换行
2、(11001010)2+(F8)16的结果是( )。
A、(11001010)2 B、(701)8 C、(1C2)16 D、(452)10
解析:(11001010)2值为202 (F8)16值为248 和为450,转为16进制为C、(1C2)16
3、表达式 4%12 的结果是( )。
A、0 B、4 C、3 D、12
解析:4%12 ,为求4除以12的余数,结果为4
4、下列选项中,逻辑表达式的值始终与 B的真假无关的是( )。
A、(!A || B) && A
B、(A || B) && (!A && B)
C、(A && !A)||B
D、(A || B) && (A || !B)
解析:D,如果A为真,该语句一定为真,如果A为假,不管B的值是否为真,该语句的值都为假,所以与B的真假无关
5、运行下面程序,输出结果是()。
- int a[6] = {16, 8, 32, 10, 9, 21};
- int func(int L, int R, int d) {
- if (L > R)
- return 0;
- int sum = 0, m = a[L], index = L;
- for (int i = L + 1; i <= R; i++) {
- if (m < a[i]) {
- m = a[i];
- index = i;
- }
- }
- int lt = func(L, index - 1, d + 1);
- int rt = func(index + 1, R, d + 1);
- return lt + rt + d * m;
- }
- int main() {
- cout << func(0, 5, 1);
- return 0;
- }
A、196 B、197 C、198 D、199
解析:A ,当func 函数被调用时,它首先检查 L 是否大于 R,这是递归的基本情况。如果 L 大于 R,函数返回 0。
函数的主要部分是一个for 循环,它在给定的索引范围[L, R] 内查找最大的元素 m 和它的索引 index。找到最大的元素后,函数对最大元素左侧和右侧的子区间进行两次递归调用,分别是 lt 和 rt,并把深度参数 d 增加 1。
最后,函数返回左递归的结果lt 加上右递归的结果 rt 再加上当前深度 d 乘以最大元素值的总和。
在main 函数中,调用 func(0, 5, 1) 开始递归处理,传入的参数表示全数组范围,从索引 0 到 5,以及初始深度 1。然后打印返回的结果,并以状态码 0 正常退出。
代码的运行结果是累加每次递归调用中找到的最大元素值乘以其深度的总和。
- 程序题
T1 看书的天数
题目描述
一本书共n页,小明计划第一天看x页,此后每一天都要比前一天多看y页,请问小明几天可以看完这本书?
输入格式
一行输入三个整数n,x,y(20<=n<=5000,1<x,y<=20) , 分别表示书的总页数、计划第一天看的页数以及此后每天都要比前一天多看的页数,整数之间以一个空格隔开
输出格式
输出一个整数,表示小明几天可以看完这本书
样例 1
样例输入 1
100 10 5
样例输出 #1
5
参考代码:
#include <iostream> // 导入输入输出流库
using namespace std; // 使用命名空间std,这样就不需要在每个标准库元素前加std::
int main() {
int n, x, y;
cin >> n >> x >> y; // 输入书的总页数、第一天计划看的页数、以及每天递增的页数
int total_pages = 0; // 初始化总页数为0
int days = 0; // 初始化天数为0
// 循环执行,每循环一次代表过去了一天,直到看的页数达到或超过总页数n为止
while (total_pages < n) {
days++; // 天数加1
total_pages += x; // 当日看的页数加到总页数上
x += y; // 计划下一天看的页数增加y
}
cout << days; // 输出完成阅读所需的天数
return 0; // 程序正常退出
}
T2 数字交换
题目描述
前导 0:整数前对数值无影响的0。
例如:
0201去除前导 0后为 201;
00321去除前导 0后为 321。
给定一个正整数 n,请将n的最高位与最低位的数字进行交换,并输出交换后的结果。如果交换后的结果有前导0,去除前导0后再输出结果。
例 1:n=173,将 173 的最高位1与最低位3 交换,交换后的结果为371;
例 2:n=10200,将 10200 的最高位1与最低位0交换,交换后的结果为 00201,结果有前导0,去除前导0后的结果为201。
输入格式
输入一个正整n(100≤n≤109)
输出格式
输出一个整数,表示将 n的最高位与最低位的数字交换后的结果如果交换后的结果有前导 0,去除前导0后再输出结果
输入输出样例
输入 #1
173
输出 #1
371
#include <iostream>
#include <string>
using namespace std;
int main() {
int n;
cin >> n; // 输入正整数n
string str = to_string(n); // 将整数n转换为字符串,便于操作每一位数字
int len = str.length(); // 获取数字的长度,即位数
// 交换字符串的第一位(最高位)和最后一位(最低位)
swap(str[0], str[len - 1]);
// 将修改后的字符串转换回整数,并自动去除前导零
int new_n = stoi(str);
cout << new_n; // 输出结果
return 0; // 程序正常结束
}
T3出现奇数次的数
题目描述
奇数:指不能被 2整除的整数。
例如:3、5是奇数;4、6不是奇数。
给定 n个整数,其中只有一个数出现了奇数次,请找出这个数。
例如:77个整数为 6、2、4、6、4、2、6,其中只有6 出现了奇数次故输出6。
输入格式
第一行输入一个整数n(1≤n≤10^5)
第二行输入 n个整数(1≤整数≤10^9) 整数之间以一个空格隔开,数据保证只有一个数出现了奇数次)
输出格式
输出一个整数,表示出现了奇数次的数
输入输出样例
输入 #1
7
6 2 4 6 4 2 6
输出 #1
6
参考程序:
要找到出现奇数次的数,我们可以使用异或运算(XOR)。在 C++ 中,异或运算用符号 ^ 表示。异或运算具有以下性质:
任何数与自己异或的结果是 0(例如,a ^ a = 0)。
任何数与 0 异或还是其本身(例如,a ^ 0 = a)。
异或运算满足交换律和结合律。
由于只有一个数出现奇数次,其余的数都出现偶数次,当我们对数组中的所有数进行异或运算时,出现偶数次的数将两两抵消变为 0,最终剩下的结果就是出现了奇数次的那个数。
#include <iostream>
using namespacestd;
int main() {
int n;
cin >> n; // 输入整数的个数n
int result = 0; // 初始化结果为0
for (int i = 0; i < n; ++i) {
int num;
cin >> num; // 输入每个整数
result ^= num; // 对结果和每个输入的整数进行异或操作
}
cout << result; // 输出异或结果即为出现奇数次的数
return 0; // 程序正常退出
}
T4 字母移位
题目描述
字母移位:表示将字母按照字母表的顺序进行移动。
例如:'b' 向右移动一位是'c’,'f'向左移动两位是'd'。
特别地,'a'向左移动一位是'z','z'向右移动一位是'a'。
给定一个仅包含小写字母且长度为 n 的字符串 s,以及 n 个正整数 a1,a2,a3……an,接下来对字符串s按如下规律操作:
1.将第 1位字符向左移动 a1 位;
2.再将第 1、2 位字符都向右移动 a2位;
3.再将第 1、2、3 位字符都向左移动 a3位;
4.再将第 1、2、3、4 位字符都向右移动 a4位;
以此类推,直到将s的第1到第n位字符都(按规律向左或向右)移动an 位。
最后,将操作完成后的字符串s输出。
例如:n=5,字符串s="abcde",5 个正整数为1,3,5,7,9;
将"abcde"的第 11 位字符"a"向左移动 1位,s变为"zbcde"
再将"zbcde"的前 2 位字符"zb" 向右移动 3 位,s变为"cecde"
再将"cecde" 的前 3位字符"cec"向左移动5 位,s 变为"xzxde"
再将"xzxde" 的前 4 位字符"xzxd"向右移动7 位,s变为"egeke"
再将"egeke"的前 5 位字符"egeke" 向左移动 9 位,s 变为"vxvbv"。
最后,将操作完成后的字符串"vxvbv"输出。
输入格式
第一行输入一个整数n(1≤n≤105)
第二行输入一个仅包含小写字母且长度为 n的字符串s
第三行输入 n个整数a1、a2…an(1≤a≤10^9),整数之间以一个空格隔开
输出格式
输出一个字符串,表示操作完成后的字符串s
输入输出样例
输入 #1
5
abcde
1 3 5 7 9
输出 #1
vxvbv
参考代码:
#include <iostream>
using namespace std;
string s; // 将要移位的字符串
int n, a[100001], b[100001]; // n 为字符串长度,a用于存储输入的每步移位量,b 用于存储前缀和
int main() {
cin >> n; // 输入字符串的长度
cin >> s; // 输入字符串
for (int i = 1; i <= n; i++) {
cin >> a[i]; // 输入每个位置的移位量
a[i] %= 26; // 将移位量对 26 取模(因为一个循环之后字母会回到原位)
if (i & 1) { // 如果 i 是奇数
a[i] *= -1; // 则反转移位的方向,因为题目要求奇数次的移位要向左
}
}
b[n] = a[n]; // 初始化 b 数组的最后一个元素
for (int i = n - 1; i >= 1; i--) {
b[i] = (a[i] + b[i + 1]) % 26; // 逆序计算 b 数组,即前缀和数组,用于存储最终的移位量
}
for (int i = 1; i <= n; i++) { // 遍历字符串中的每个字符
int x = s[i - 1] - 96; // 字母转换为 1-26 的数字('a' 转换为 1,'z' 转换为 26)
if ((x + b[i]) % 26 == 0) { //如果移位后字母应该变成 'z'
s[i - 1] = 'z';
continue;
}
s[i - 1] = char((x + b[i] + 26) % 26 + 96); // 应用最终的移位量,并将数字转换回字符
}
cout << s; // 输出移位后的字符串
return 0; // 程序正常结束
}
T5能量
有一款新游戏,通关这个游戏需要完成n个任务,这n个任务可按任意次序完成,每个任务设置了启动能量值和完成任务消耗的能量值,且消耗的能量值小于等于该任务的启动能量值,如果玩家当前的能量值低于该任务启动能量值则不能开始该任务。
例 1:玩家当前的能量值为 7,当前任务的启动能量值为 5,完成任务消耗的能量值为 3,则可以开始该任务,完成任务后玩家剩余能量值为4
例 2:玩家当前的能量值为 5,当前任务的启动能量值为 8,则无法开始该任务。
游戏开始时玩家需要一个初始能量值用来完成这 n个任务,当给定每个任务的启动能量值和完成任务消耗的能量值,请问初始能量的最小值是多少?
例如:n=3,这3个任务的启动能量值和完成任务消耗的能量值分别是:(2,2)、(9,5)、(7,4),那么玩家初始能量的最小值为12。可按照如下顺序完成任务:
1.完成任务(9,5),玩家剩余能量值为 7;
2.完成任务(7,4)玩家剩余能量值为 3;
3.完成任务(2,2),玩家剩余能量值为 1.
尽管最后玩家的能量值还剩余 1,但是初始能量值无法再降低,否则完成任务(9,5)后,玩家的剩余能量值会小于任务(7,4)的启动能量值,导致无法开始该任务。
输入格式
共n+1行
第一行输入一个整数n(1≤n≤105),表示游戏的任务数量
接下来n行,每行输入两个整x,y(1≤y≤x≤1000),分别表示当前任务所需的启动能量值和完成任务所消耗的能量值,整数之间以一个空格隔开
输出格式
输出一个整数,表示玩家要完成这 n个任务需要的初始能量的最小
输入输出样例
输入
3
2 2
9 5
7 4
输出
12
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct Task {
int start;
int consume;
};
bool compareTask(const Task &a, const Task &b) {
// 启动能量值大,或者能量差值(节省)大的任务排在前面
return a.start - a.consume > b.start - b.consume;
}
int main() {
int n;
cin >> n;
vector<Task> tasks(n);
for (int i = 0; i < n; ++i) {
cin >> tasks[i].start >> tasks[i].consume;
}
// 根据启动减去消耗的值来排序任务
sort(tasks.begin(), tasks.end(), compareTask);
long long initEnergy = 0; // 需要的最小初始能量值
long long currentEnergy = 0; // 当前的能量值
// 从节省能量最大的任务开始
for (auto &task : tasks) {
// 如果当前能量不能启动任务,则需要增加初始能量
if (currentEnergy < task.start) {
// 增加的能量为启动能量值减去当前能量值
initEnergy += task.start - currentEnergy;
// 当前能量增加至启动能量值
currentEnergy = task.start;
}
// 启动任务后,消耗相应的能量
currentEnergy -= task.consume;
}
cout << initEnergy;
return 0;
}
T6 物品拆分
n件物品排成一排,编号分别为: 1、2、3...n身的价值,价值分别为:a1、a2、a3...an
请将这 n件物品拆分为k组(不改变物品的顺序),要求每组内至少有一件物品,分别统计每组物品的价值之和,并找出其中的最大值。请设计一种分组方案,使这个最大值尽可能小,并输出这个最大值。
例如:n=5,表示有5 件物品,这5 件物品的价值分别是 6、1、3、8、4;k=2,表示要将这 5 件物品拆分为两组,有如下方案:
1.[6]和 [1,3,8,4],两组物品各自的价值之和为 6和 16,最大值为16;
2.[6,1]和 [3,8,4],两组物品各自的价值之和为 7和 15,最大值为15;
3.[6,1,3]和 [8,4],两组物品各自的价值之和为 10 和 12,最大值为 12;
4.[6,1,3,8]和 [4],两组物品各自的价值之和为 18 和 4,最大值为18;
其中第 3 种方案,价值之和的最大值12 在 4 种方案中最小,故输出12.
输入格式
第一行输入一个整数n(1≤n≤1000),表示物品的数量
第二行输入 n 个整数a1、a2,...an(1≤ai≤105),ai表示i号物品的价值,整数之间以一个空格隔开
第三行输入一个整数k(1≤k≤n),表示将n件物品拆分的组数
输出格式
输出一个整数,表示按照题目要求得到的最大值
输入输出样例
输入
5
6 1 3 8 4
2
输出
12
#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
using namespace std;
bool check(const vector<int>& values, int mid, int k) {
int count = 1; // 分组计数
int sum = 0;
for (auto v : values) {
if (sum + v > mid) {
count++;
sum = v;
if (count > k) return false; // 如果分组数超过k,则不符合条件
} else {
sum += v;
}
}
return true;
}
int main() {
int n, k;
cin >> n;
vector<int> values(n);
int sum_val = 0;
int max_val = INT_MIN;
for (int i = 0; i < n; i++) {
cin >> values[i];
sum_val += values[i];
max_val = max(max_val, values[i]);
}
cin >> k;
// 二分搜索
int left = max_val, right = sum_val;
while (left < right) {
int mid = left + (right - left) / 2;
if (check(values, mid, k)) { // 检查mid是否可行
right = mid; // 尝试降低上界
} else {
left = mid + 1; // 如果不可行,提高下界
}
}
cout << left << endl; // 输出最小的最大值
return 0;
}