2024年蓝桥杯第十五届CC++大学B组真题及代码
目录
1A:握手问题(填空5分)
解析代码_数学_正解
2B:小球反弹(填空5分)
解析代码_数学_正解
3C:好数(编程10分)
解析代码_暴力_正解
4D:R 格式(编程10分)
解析代码_高精度_正解
5E:宝石组合(编程15分)
解析代码_dp_正解
6F:数字接龙(编程15分)
解析代码_dfs_正解
7G:爬山(编程20分)
解析代码_贪心_有争议
8H:拔河(编程20分)
解析代码_双指针二分_正解
本篇完。
题库链接:题库 - 蓝桥云课
1A:握手问题(填空5分)
问题描述
小蓝组织了一场算法交流会议,总共有 50 人参加了本次会议。在会议上,大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手 (且仅有一次)。但有 77 个人,这 7 人彼此之间没有进行握手 (但这 7 人与除这 7 人以外的所有人进行了握手)。请问这些人之间一共进行了多少次握手?
注意 A 和 B 握手的同时也意味着 B 和 A 握手了,所以算作是一次握手。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
解析代码_数学_正解
比较简单的填空题,可以用组合数学计算,也可以分成两堆人来思考。
43个人每人握手42个人(彼此握手需要/2),有7个人需要握手43个人 。
#include <iostream>
using namespace std;
int main()
{cout << 43 * 42 / 2 + 43 * 7 <<endl;return 0;
}
2B:小球反弹(填空5分)
问题描述
有一长方形,长为 343720 单位长度,宽为 233333 单位长度。在其内部左上角顶点有一小球 (无视其体积),其初速度如图所示且保持运动速率不变,分解到长宽两个方向上的速率之比为 dx:dy=15:17。小球碰到长方形的边框时会发生反弹,每次反弹的入射角与反射角相等,因此小球会改变方向且保持速率不变(如果小球刚好射向角落,则按入射方向原路返回)。从小球出发到其第一次回到左上角顶点这段时间里,小球运动的路程为多少单位长度?答案四舍五入保留两位小数。
答案提交
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个小数,在提交答案时只填写这个小数,填写多余的内容将无法得分。
解析代码_数学_正解
也是数学题,最终返回左上角时,走过的水平路程和垂直路程一定是343720 和233333 的偶数倍,并且水平路程与垂直路程之比一定为15 : 17 。写暴力去找结果即可,答案是1100325199.77
#include<bits/stdc++.h>
#define int long longusing namespace std;
const int W = 233333;
const int L = 343720;signed main()
{for (int x = 2; x <= 10000; x += 2){for (int y = 2; y <= 10000; y += 2){if (15 * W * y == 17 * L * x){printf("%.2llf", sqrt((L * x) * (L * x) + (W * y) * (W * y)));return 0;}}}return 0;
}
3C:好数(编程10分)
解析代码_暴力_正解
正解应该是数位dp,但是感觉数据不大,暴力枚举也能过。
#include <iostream>#define int long long
#define endl '\n'
using namespace std;bool inline judge(int x)
{int k = 1;while (x){if ((x & 1) != (k & 1))return false;x /= 10;k++;}return true;
}signed main()
{ios::sync_with_stdio(0); // 关流cin.tie(0);cout.tie(0);int n = 0;cin >> n;int res = 0;for (int i = 1; i <= n; i += 2){if (judge(i))++res;}cout << res << endl;return 0;
}
4D:R 格式(编程10分)
小蓝最近在研究一种浮点数的表示方法:R 格式。对于一个大于 0 的浮点数 d,可以用 R 格式的整数来表示。给定一个转换参数 n,将浮点数转换为 R 格式整数的做法是:
-
将浮点数乘以 2^n;
-
四舍五入到最接近的整数。
输入格式
一行输入一个整数 n 和一个浮点数 d,分别表示转换参数,和待转换的浮点数。
输出格式
输出一行表示答案:d 用 R 格式表示出来的值。
样例输入
2 3.14
样例输出
13
样例说明
3.14×2^2 = 12.56,四舍五入后为 13。
解析代码_高精度_正解
高精度加和乘
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;string add(string s, string t)
{int end1 = s.size() - 1, end2 = t.size() - 1;string ret;int carry = 0;while(end1 >= 0 || end2 >= 0){int val1 = end1 >= 0 ? s[end1] - '0' : 0;int val2 = end2 >= 0 ? t[end2] - '0' : 0;ret += (val1 + val2 + carry) % 10 + '0';if(val1 + val2 + carry > 9)carry = 1;elsecarry = 0;--end1;--end2;}if(carry)ret += '1';reverse(ret.begin(), ret.end());return ret;
}string mul(string num1, string num2)
{int n1 = num1.size(), n2 = num2.size();vector<int> tmp(n1 + n2 - 1);reverse(num1.begin(), num1.end());reverse(num2.begin(), num2.end());for(int i = 0; i < n1; ++i){for(int j = 0; j < n2; ++j){tmp[i+j] += (num1[i] - '0') * (num2[j] - '0');}}string ret = "";int carry = 0;for(auto& e : tmp){ret += ((e + carry) % 10 + '0');carry = (e + carry) / 10; }if(carry)ret += (carry + '0');while(ret.size() > 1 && ret.back() == '0') ret.pop_back(); // 处理前导0reverse(ret.begin(), ret.end());return ret;
}signed main()
{ios::sync_with_stdio(0); // 关流cin.tie(0);cout.tie(0);int n = 0;string d;cin >> n >> d;string res = "1";for (int i = 0; i < n; i++){res = mul(res, "2");}int pos = 0;while (d[d.size() - 1 - pos] != '.'){pos++;}res = mul(res, d.substr(0, d.size() - pos - 1) + d.substr(d.size() - pos));string remain = "5";for (int i = 0; i < pos - 1; i++){remain += "0";}res = add(res, remain);cout << res.substr(0, res.size() - pos) << endl;return 0;
}
5E:宝石组合(编程15分)
问题描述
在一个神秘的森林里,住着一个小精灵名叫小蓝。有一天,他偶然发现了一个隐藏在树洞里的宝藏,里面装满了闪烁着美丽光芒的宝石。这些宝石都有着不同的颜色和形状,但最引人注目的是它们各自独特的 “闪亮度” 属性。每颗宝石都有一个与生俱来的特殊能力,可以发出不同强度的闪光。小蓝共找到了 N 枚宝石,第 i 枚宝石的 “闪亮度” 属性值为 Hi,小蓝将会从这 N 枚宝石中选出三枚进行组合,组合之后的精美程度 S 可以用以下公式来衡量:
其中 LCM 表示的是最小公倍数函数。
小蓝想要使得三枚宝石组合后的精美程度 S 尽可能的高,请你帮他找出精美程度最高的方案。如果存在多个方案 S 值相同,优先选择按照 H 值升序排列后字典序最小的方案。
输入格式
第一行包含一个整数 N 表示宝石个数。
第二行包含 N 个整数表示 N 个宝石的 “闪亮度”。
输出格式
输出一行包含三个整数表示满足条件的三枚宝石的 “闪亮度”。
样例输入
5
1 2 3 4 9
样例输出
1 2 3
解析代码_dp_正解
找最大gcd(a[i],a[j],a[k]),里面的最小的三个数
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;int a[100100], b[100100];
vector<int> vec[100100];signed main()
{ios::sync_with_stdio(0); // 关流cin.tie(0);cout.tie(0);int n = 0;cin >> n;int max_a = 0;for (int i = 1; i <= n; i++){cin >> a[i];b[a[i]]++;max_a = max(max_a, a[i]);}sort(a + 1, a + 1 + n);for (int i = 2; i <= max_a; i++){for (int j = i; j <= max_a; j += i){for (int k = 1; k <= b[j]; k++){if (vec[i].size() >= 3)break;vec[i].push_back(j);}}}for (int i = max_a; i >= 2; i--){if (vec[i].size() >= 3){cout << vec[i][0] << " " << vec[i][1] << " " << vec[i][2] << endl;return 0;}}cout << a[1] << " " << a[2] << " " << a[3] << endl;return 0;
}
6F:数字接龙(编程15分)
解析代码_dfs_正解
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 11;
int n, k;
int g[N][N];
int dx[] = {-1, -1, 0, 1, 1, 1, 0, -1};
int dy[] = {0, 1, 1, 1, 0, -1, -1, -1};
string path;
bool st[N][N], edge[N][N][N][N];bool dfs(int a, int b)
{if (a == n - 1 && b == n - 1){return path.size() == n * n - 1;}st[a][b] = true;for (int i = 0; i < 8; i++){int x = a + dx[i], y = b + dy[i];if (x < 0 || x >= n || y < 0 || y >= n)continue;if (st[x][y])continue;if (g[x][y] != (g[a][b] + 1) % k)continue;if (i % 2 && (edge[a][y][x][b] || edge[x][b][a][y]))continue;edge[a][b][x][y] = true;path += i + '0';if (dfs(x, y))return true;path.pop_back();edge[a][b][x][y] = false; // 恢复现场}st[a][b] = false; // 恢复现场return false;
}int main()
{cin >> n >> k;for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)cin >> g[i][j];if (!dfs(0, 0))cout << -1 << endl;elsecout << path << endl;return 0;
}
7G:爬山(编程20分)
解析代码_贪心_有争议
贪心是官方题解,但是有些数据过不了。
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;
const int N = 1e5 + 10; // 定义常量N,表示最大可能的输入规模int main()
{priority_queue<int> pq; // 声明一个大根堆,用于维护当前最大值int n, p, q; cin >> n >> p >> q; // 输入数字个数n,以及操作次数p和qfor (int i = 1; i <= n; i++) // 输入n个数字并加入堆中{int x; cin >> x;pq.push(x);}while (p || q) // 当还有操作次数时循环处理{int cur = pq.top(); // 获取当前最大值pq.pop(); // 移除当前最大值if (p) // 贪心优先执行p操作(开平方){cur = sqrt(cur); // 对当前值开平方p--; // 减少p操作次数}else if (q) // 当p操作用完时执行q操作(除以2){cur /= 2; // 当前值除以2q--; // 减少q操作次数}pq.push(cur); // 将处理后的值重新加入堆中}int s = 0; // 计算堆中所有元素的和while (!pq.empty()){s += pq.top(); // 累加堆顶元素pq.pop(); // 移除堆顶元素}cout << s << endl; // 输出最终结果return 0;
}
8H:拔河(编程20分)
解析代码_双指针二分_正解
#include <bits/stdc++.h>
#define int long long // 使用长整型
#define endl '\n'
using namespace std;
int num[1010] = {0}; // 存储原始数组
int pre[1010] = {0}; // 前缀和数组
multiset<int> mset; // 用于存储所有可能的子数组和signed main()
{ios::sync_with_stdio(0); // 关闭同步流以提高输入输出效率cin.tie(0);cout.tie(0);int n = 0;cin >> n; // 输入数组长度for (int i = 1; i <= n; i++) {cin >> num[i]; // 输入数组元素pre[i] = pre[i - 1] + num[i]; // 计算前缀和}for (int l = 1; l <= n; l++) // 生成所有可能的子数组和并存入multiset{for (int r = l + 1; r <= n; r++) {mset.insert(pre[r] - pre[l]); // 计算并存储子数组和}}int res = INT_MAX; // 初始化结果为最大值for (int r = 1; r < n; r++) {for (int l = 0; l < r; l++) {int val = pre[r] - pre[l]; // 计算当前子数组和auto it = mset.lower_bound(val); // 在multiset中查找最接近val的值if (it != mset.end()) {res = min(res, abs(*it - val)); // 更新最小差值}if (it != mset.begin()) {it--;res = min(res, abs(*it - val)); // 更新最小差值}}for (int i = r + 1; i <= n; i++) // 动态维护multiset,移除不再需要的子数组和{mset.erase(mset.find(pre[i] - pre[r]));}}cout << res << endl; // 输出结果return 0;
}/*
输入示例:
5
10 9 8 12 14
*/
本篇完。
开始没有第九第十题了。