2024年蓝桥杯第十五届C&C++大学B组真题及代码

发布于:2025-04-15 ⋅ 阅读:(20) ⋅ 点赞:(0)

目录

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 long
 
using 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 格式整数的做法是:

  1. 将浮点数乘以 2^n;

  2. 四舍五入到最接近的整数。

输入格式

一行输入一个整数 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;
        else
            carry = 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(); // 处理前导0

    reverse(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;
    else
        cout << 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和q
    for (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; // 当前值除以2
            q--; // 减少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
*/

本篇完。

开始没有第九第十题了。