第十三届蓝桥杯模拟赛(第一期)试题与题解 C++

第十三届蓝桥杯模拟赛(第一期)试题与题解

找了好久才找到第一期的题目,题目来自一位老哥文章中截图,感谢这位老哥!
第十三届蓝桥杯模拟赛(第一期)题解
因为有些题目的截图不完整,所以可能缺少输入样例和样例规模

1、试题A

【问题描述】

​ 请问在 10000 (含)到 90000 (含)中,有多少个数是 128 的倍数。

【答案提交】

​ 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

方法一:遍历

//答案 625
#include <iostream>
using namespace std;

int main() {
	int ans = 0;
	for (int i = 10000; i <= 90000; i++) {
		if (i % 128 == 0) ans++;
	}
	cout << ans << endl;
	return 0;
}

方法二:直接计算

//答案 625
#include <iostream>
using namespace std;

int main() {
	int a = 10000, b = 90000;
	int ans = (b - a) / 128 + (a % 128 > b % 128 || a % 128 == 0);
	cout << ans << endl;
	return 0;
}

2、试题B

【问题描述】

​ 2021 是一个特殊的年份,它的千位和十位相同,个位比百位多一。请问从 1000 (含)到 9999 (含)有多少个这样的年份?

【答案提交】

​ 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

方法一:遍历

//答案 81
#include <iostream>
using namespace std;

int main() {
	int ans = 0;
	for (int i = 1000; i <= 9999; i++) {
		int a = i / 1000, b = (i / 100) % 10, c = (i / 10) % 10, d = i % 10;
		if (a == c && d == b + 1) ans++;
	}
	cout << ans << endl;
	return 0;
}

方法二:直接计算

在千位确定时,十位与千位相同,个位比百位大一的可能有 9 种
从 100099999 个不同的千位
所以答案是 9 * 9 = 81

3、试题C

【问题描述】

​ 如果 1 到 n 的一个排列中,所有奇数都在原来的位置上,称为一个奇不动排列。

​ 例如,1 到 7 的排列 (1, 6, 3, 4, 5, 2, 7)是一个奇不动排列,因为1, 3, 5, 7都在原来的位置上。请问,1 到 21 的所有排列中,有多少个奇不动排列。

【答案提交】

​ 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

题解

1 ~ 21 之间有 10 个偶数,奇数的位置不变,10 个偶数在 10 个位置上的全排列就是答案,即 10!

//答案 3628800
#include <iostream>
using namespace std;

int main() {
	int ans = 1;
	for (int i = 1; i <= 10; i++){
		ans *= i;
	}
	cout << ans << endl;
	return 0;
}

4、试题D

【问题描述】

​ 小蓝要上一个楼梯,共 15 级台阶。

​ 小蓝每步可以上 1 级台阶,也可以上 2 级、3 级或 4 级,再多就没办法一步走到了。

​ 每级台阶上有一个数值,可能正也可能负。每次走到一级台阶上,小蓝的得分就加上这级台阶上的数值。台阶上的数值依次为: 1, 2, 1, 1, 1, 1, 5, 5, 4, -1, -1, -2, -3, -1, -9。

​ 小蓝希望不超过 6 步走到台阶顶端,请问他得分的最大值是多少?

​ 注意,小蓝开始站在地面上,地面没有分值。他最终要走到台阶顶端,所以最终一定会走到数值为 -9 的那级台阶,所以 -9 一定会加到得分里面。

【答案提交】

​ 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

题解:深搜

//答案 5
#include <iostream>
using namespace std;
const int INF = 0x3f3f3f3f;

int a[16] = {0, 1, 2, 1, 1, 1, 1, 5, 5, 4, -1, -1, -2, -3, -1, -9};

int dfs(int idx, int k) {
	if (idx == 15) return a[15];
	if (k == 6) return -INF;
	int ans = -INF;
	for (int i = 1; i <= 4 && idx + i <= 15; i++) {
		ans = max(ans, dfs(idx + i, k + 1));
	}
	return ans + a[idx];
}

int main() {
	cout << dfs(0, 0) << endl;
	return 0;
}

5、试题E

【问题描述】

​ 在数列 a[1], a[2] … a[n] 中,如果对于下标 i, j, k 满足 0 < i < j < k < n + 1 且 a[i] < a[j] < a[k], 则称 a[i], a[j], a[k] 为一组递增三元组。

​ 请问对于下面的长度为20的数列,有多少个递增三元组?

​ 2, 9, 17, 4, 14, 10, 25, 26, 11, 14, 16, 17, 14, 21, 16, 27, 32, 20, 26, 36。

【答案提交】

​ 这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

题解:枚举

//答案 565
#include <iostream>
using namespace std;

int a[20] = {2, 9, 17, 4, 14, 10, 25, 26, 11, 14, 16, 17, 14, 21, 16, 27, 32, 20, 26, 36};

int main() {
	int ans = 0;
	int n = 20;
	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {
			for (int k = j + 1; k < n; k++) {
				if (a[i] < a[j] && a[j] < a[k]) ans++;
			}
		}
	}
	cout << ans << endl;
	return 0;
}

6、试题F

【问题描述】

​ 小蓝开车在高速上行驶了t 小时,速度固定为每小时 v 千米,请问小蓝在高速上行驶了多长路程?

【输入格式】

​ 输入一行包含两个整数 t、v,用一个空格分隔。

【输出格式】

​ 输出一行包含—个整蚁,表示答室。

【样例输入】

3 81

【样例输出】

243

【评测用例规模与约定】

对于所有评测用例, 1 <= t <= 10,1 <= v <= 150。

题解

#include <iostream>
using namespace std;

int main() {
	int v, t;
	cin >> t >> v;
	cout << t * v << endl;
	return 0;
}

7、试题G

【问题描述】

​ 有一个n * m 的棋盘,现在对这个棋盘进行黑白染色,左上角染成黑色。从左上角开始,每个黑色格的相邻格染成白色,白色格的相邻格染成黑色。

​ 以下给出了一个5 * 7的棋盘的染色示例。

​ (示例部分未找到 ,可以理解为已经被染色的格子不会再次被染色)

​ 给定 n 和 m,请问棋盘上一共有多少方格被染成了黑色。

【输入格式】

​ 输入一行包含两个整数n, m,用一个空格分隔。

【输出格式】

​ 输出一行包含—个整数,表示答案。

【样例输入】

5 7

【样例输出】

18

【评测用例规模与约定】

​ 对于50%的评测用例,1 <= n, m <= 10000,
​ 对于所有评测用例,1 <= n, m <= 1000000。

方法一:逐行计数

​ 对于每行的格子来说,黑色与白色是被交替染色的,若第 1 列是黑色,那么该行黑色格子数是奇数列数,否则就是偶数列数,也可知奇数行是黑色开头(行与列从 1 开始数)

​ 可以使用一个布尔值,交替表示当前行是奇数行还是偶数行

#include <bits/stdcpp.h>
using namespace std;
typedef long long ll;

int main() {
	ll m, n, ans = 0;
	bool f = true;
	cin >> m >> n;
	if (m > n) swap(m, n);	//m,n可以互换,结果不变 
	for (int i = 0; i < m; i++) {
		ans += (n + f) / 2;	//(n+1)/2表示1~n之间的奇数个数
		f = !f;
	}
	cout << ans << endl;
	return 0;
}

方法二:直接计算

​ 可以发现当行号与列号相加为偶数是,该格子是黑色,此时有两种情况:行号列号都是奇数,或者行号列号都是偶数,所以答案是:奇行个数 × 奇列个数 + 偶行个数 × 偶列个数 (行与列从 1 开始数)

#include <bits/stdcpp.h>
using namespace std;
typedef long long ll;

int main() {
	ll m, n, ans = 0;
	cin >> m >> n;
	ans += ((m + 1) / 2) * ((n + 1) / 2);
	ans += (m / 2) * (n / 2);	//涉及到取整问题,括号不能少
	cout << ans << endl;
	return 0;
}

方法三:最简单的直接计算

将棋盘每两行分为一组,容易发现每组中黑色格子占每组总格子数的一半
假设棋盘为 m 行 n 列
如果 m 为偶数,答案是所有格子数的一半,即 m * n / 2
如果 m 为奇数,答案是 (m - 1) * n / 2 + (n + 1) / 2 = (m * n + 1) / 2
又发现 m 为偶数时答案也可写成 (m * n + 1) / 2

#include <bits/stdc++.h>
using namespace std;

int main() {
	int m, n;
	cin >> m >> n;
	cout << (m * n + 1) / 2 << endl;
	return 0;
}

8、试题H

【问题描述】

​ 小蓝要在路边划分停车位。

​ 他将路边可停车的区域划分为 L个整数小块,编号1至L。一个车位需要连续的 K 个小块,停车位不能重叠。有的小块属于井盖、消防通道等区域,不能停车。

​ 请问小蓝最多划分出多少个停车位?

【输入格式】

​ 输入的第一行包含三个整数 L、K、N,分别表示小块数量、一个车位需要的小块数量和不能停车的小块数量,相邻整数之间用一个空格分隔。

​ 第二行包含 N 个整数a[1], a[2], …, a[n],按从小到大的顺序排列,相邻的整数间用空格分隔,表示这些位置不能停车。

【输出格式】

​ 输出一行包含一个整数,表示答案。

【样例输入】

100 10 2
25 91

【样例输出】

8

【评测用例规模与约定】

​ 该部分未找到

题解

注意输入格式,第二行的输入会按从小到大的顺序排列

#include <iostream>
using namespace std;

int main() {
	int  len, k, n;
	cin >> len >> k >> n;
	int ans = 0, last = 0, tmp;
	for (int i = 0; i < n; i++) {
		cin >> tmp;
		ans += (tmp - last - 1) / k;
		last = tmp;
	}
	ans += (len + 1 - last - 1) / k;
	cout << ans << endl;
	return 0;
}

9、试题 I

【问题描述】

​ 一个 1 到 n 的排列被称为人字排列,是指排列中的第 1 到第 (n + 1) / 2 个元素单调递增,第 (n + 1) / 2 到第 n 个元素单调递减。

​ 例如: (2, 3, 5, 8, 9, 7, 6, 4, 1)是一个人字排列,而 (1, 2, 3) 和 (2, 1, 3) 都不是人字排列,(2, 4, 3) 也不是一个人字排列 (它甚至不是一个 1 到 4 的排列) 。

​ 请问,1 到 n 的排列中有多少个人字排列?

【输入格式】

​ 输入一行包含一个奇数 n。

【输出格式】

​ 输出一行包含一个整数,表示答案,答案可能很大,请输出答案除以1000000007的余数。

【样例输入】

5

【样例输出】

6

【评测用例规模与约定】

​ 该部分未找到

题解

注意输入的 n 一定为奇数

​ 最大的数一定固定在中间位置,再从剩下的 (n - 1) 个数中选出 (n / 2) 个数升序排列放在左边,剩下的 (n / 2) 个数降序排列放在右边,所以答案是 C(n - 1, n / 2)

#include <iostream>
using namespace std;
const int MOD = 1E9 + 7;
//求从a中取b个的组合数 
int getc(int a, int b) {
	b = min(b, a - b); 
	long long ans = 1;
	for (int i = 0; i < b; i++) {
		ans = (ans * (a - i) / (i + 1)) % MOD;
	}
	return ans;
}

int main() {
	int n;
	cin >> n;
	cout << getc(n - 1, n / 2) << endl;
	return 0;
}

10、试题J

【问题描述】

​ 著名设计师小蓝给蓝桥小学设计了一个教学楼。

​ 蓝桥小学经常下雨,所以校长希望教学楼任何地方都可以连通到其它地方。

​ 小蓝给出了教学楼的平面图,用一个 n 行 m 列的 01 矩阵表示,其中 0 表示空地,1 表示教学楼。两个相邻的 1 (上下相邻或左右相邻)之间互相可达。

​ 请帮小蓝检查一下,是否教学楼的任意两个地方都可以连通到其它地方。

【输入格式】

​ 输入的第一行包含两个整数 n, m,用一个空格分隔。接下来n行,每行一个长度为 m 的 01 串,表示教学楼的平面图。

【输出格式】

​ 如果满足要求,输出“YES”,否则输出“NO”,请注意字母全部都是大写。

【样例输入】

​ 以下部分未找到

方法一:广搜

题解中将 m 与 n 互换了,m 表示行,n 表示列

#include <bits/stdcpp.h>
using namespace std;
int m, n;
vector<string> mp;
int a[][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

bool find1(int &x, int &y) {
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			if (mp[i][j] == '1') {
				x = i, y = j;
				return true;
			}
		}
	}
	return false;
} 
int main() {
	cin >> m >> n;
	mp.resize(m);
	for (int i = 0; i < m; i++) {
		cin >> mp[i];
	}
	int x, y;
	if (!find1(x, y)) {
		cout << "TES" << endl;
		return 0;
	}
	queue<pair<int, int> > q;
	mp[x][y] = '0';
	q.push(make_pair(x, y));
	while (!q.empty()) {
		x = q.front().first;
		y = q.front().second;
		q.pop();
		for (int i = 0; i < 4; i++) {
			int xx = x + a[i][0];
			int yy = y + a[i][1];
			if (xx >= 0 && xx < m && yy >= 0 && yy < n && mp[xx][yy] == '1') {
				mp[xx][yy] = '0';
				q.push(make_pair(xx, yy));
			}
		}
	}
	if (find1(x, y)) cout << "NO" << endl;
	else cout << "YES" << endl;
	return 0;
}

​ 也可用 cnt 记录矩阵中 ‘1’ 的个数,每放入队列一个坐标,就令 cnt -= 1,最后判断 cnt 是否等于 0 即可,如在方法二深搜中,每递归一次,就将 cnt -= 1

方法二:深搜

深搜有爆栈的风险,这样的题还是该广搜比较好……

#include <bits/stdcpp.h>
using namespace std;
int m, n, cnt = 0;
vector<string> mp;
int a[][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

bool find1(int &x, int &y) {
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			if (mp[i][j] == '1') {
				if (cnt == 0) x = i, y = j;
				cnt++;
			}
		}
	}
	return cnt;
}
void dfs(int x, int y) {
	for (int i = 0; i < 4; i++) {
		int xx = x + a[i][0];
		int yy = y + a[i][1];
		if (xx >= 0 && xx < m && yy >= 0 && yy < n && mp[xx][yy] == '1') {
			mp[xx][yy] = '0';
			cnt--;
			dfs(xx, yy);
		}
	}
} 

int main() {
	cin >> m >> n;
	mp.resize(m);
	for (int i = 0; i < m; i++) {
		cin >> mp[i];
	}
	queue<pair<int, int> > q;
	int x, y;
	if (!find1(x, y)) {
		cout << "TES" << endl;
		return 0;
	}
	cnt--;
	mp[x][y] = '0';
	dfs(x, y);
	if (cnt) cout << "NO" << endl;
	else cout << "YES" << endl;
	return 0;
}
  • 16
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值