蓝桥杯十五届c++B组真题题解

试题A:握手问题

#include <iostream>
using namespace std;

int main()
{
    int count = 0;
    for (int i = 0; i < 50; i++)
        for (int j = i + 1; j < 50; j++)
            count++;

    for (int i = 0; i < 7; i++)
        for (int j = i + 1; j < 7; j++)
            count--;

    cout << count;
    return 0;
}

 先将50个人之间握手的次数求出,再减去7个人之间相互握手的次数即可

试题B:小球反弹

#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
 
int gcd(int a,int b)
{
  return b==0?a:gcd(b,a%b);
}

int main() {
    int y = 233333;
    int x = 343720;
    int p=15*y;
    int q=17*x;
    int g=gcd(p,q);
    p/=g;
    q/=g;
    int t=2*p*x/15;
    double ans=t*sqrt(15*15+17*17)*1.0;
    printf("%.2lf",ans);
    return 0;
}

 设小球在x的方向上走了p个来回,在y方向上走了q个来回,经过了时间t后回到了起点

则t*dx=2px,t*dy=2qy,化简可得p/q=dx*y/dy*x,t=2*p*x/dx

试题C:好数 

题目描述

一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位 · · · )上的数字是奇数,偶数位(十位、千位、十万位 · · · )上的数字是偶数,我们就称之为“好数”。给定一个正整数 N,请计算从 1 到 N 一共有多少个好数。

输入格式

一个整数 N。

输出格式

一个整数代表答案。

样例输入

24

样例输出

7

提示

对于第一个样例,24 以内的好数有 1、3、5、7、9、21、23,一共 7 个。试题 C: 好数 4第十五届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组【评测用例规模与约定】对于 10% 的评测用例,1 ≤ N ≤ 100。对于 100% 的评测用例,1 ≤ N ≤ 107。

#include <iostream>
using namespace std;
int main()
{
    int count = 0, n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int x = i,flag = 1;
        while (x)
        {
            int y = x % 10;
            x /= 10;
            if (flag == 1)
            {
                if (y % 2 == 0)
                {
                    flag = 0;
                    break;
                }
            }
            else
            {
                if (y % 2 != 0)
                {
                    flag = 0;
                    break;
                }
            }
            flag *= -1;
        }
        if (flag != 0) count++;
    }    
    cout << count;
    return 0;
}

试题D:R格式

题目描述

小蓝最近在研究一种浮点数的表示方法:R 格式。对于一个大于 0 的浮点数 d,可以用 R 格式的整数来表示。给定一个转换参数 n,将浮点数转换为 R格式整数的做法是:

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

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

输入格式

一行输入一个整数 n 和一个浮点数 d,分别表示转换参数,和待转换的浮点数。

输出格式

输出一行表示答案:d 用 R 格式表示出来的值。

样例输入

2 3.14

样例输出

13

提示

【样例说明】

3.14 × 22 = 12.56,四舍五入后为 13。

【评测用例规模与约定】

对于 50% 的评测用例:1 ≤ n ≤ 10,1 ≤ 将 d 视为字符串时的长度 ≤ 15。

对于 100% 的评测用例:1 ≤ n ≤ 1000,1 ≤ 将 d 视为字符串时的长度≤ 1024;保证 d 是小数,即包含小数点。

#include <iostream>
#include<vector>

using namespace std;

int main()
{
    int n;
    cin >> n;
    string s;
    cin >> s;
    for (int i = 0; i < n; i++)
    {
        int sum = 0;
        for (int j = s.size() - 1; j >= 0; j--)
        {
            if (s[j] == '.') continue;
            int sum2 = (s[j] - '0') * 2;
            s[j] = ((sum2 + sum) % 10) + '0';
            sum = sum2 / 10; 
            if (j == 0 && sum != 0)
            {
                s.insert(s.begin(), sum + '0');
            }
        }
    }

    for (int i = 0; i < s.size(); i++)
    {
        if (s[i] == '.')
        {
            if (i + 1 < s.size() && s[i + 1] - '0' >= 5)
            {
                int sum = 1;
                for (int j = i - 1; j >= 0; j--)
                {
                    int x = s[j] - '0';
                    x += sum;
                    s[j] = x % 10 + '0';
                    sum = x / 10;
                    if (sum == 0) break;
                }
                if (sum > 0) s.insert(s.begin(), sum + '0');
            }
            break;
        }
    }

    for (int i = 0; i < s.size(); i++)
    {
        if (s[i] == '.') break;
        cout << s[i];
    }
    return 0;
}

这道题使用的是高精度乘法,第一个for循环是乘法,第二个for循环是对数据进行四舍五入

试题F:数字接龙

小蓝最近迷上了一款名为《数字接龙》的迷宫游戏,游戏在一个大小为N × N 的格子棋盘上展开,其中每一个格子处都有着一个 0 . . . K − 1 之间的整数。游戏规则如下:

1. 从左上角 (0, 0) 处出发,目标是到达右下角 (N − 1, N − 1) 处的格子,每一步可以选择沿着水平/垂直/对角线方向移动到下一个格子。

2. 对于路径经过的棋盘格子,按照经过的格子顺序,上面的数字组成的序列要满足:0, 1, 2, . . . , K − 1, 0, 1, 2, . . . , K − 1, 0, 1, 2 . . . 。

3. 途中需要对棋盘上的每个格子恰好都经过一次(仅一次)。

4. 路径中不可以出现交叉的线路。例如之前有从 (0, 0) 移动到 (1, 1),那么再从 (1, 0) 移动到 (0, 1) 线路就会交叉。

为了方便表示,我们对可以行进的所有八个方向进行了数字编号,如下图2 所示;因此行进路径可以用一个包含 0 . . . 7 之间的数字字符串表示,如下图 1是一个迷宫示例,它所对应的答案就是:41255214。

蓝桥杯2024年第十五届省赛真题-数字接龙

现在请你帮小蓝规划出一条行进路径并将其输出。如果有多条路径,输出字典序最小的那一个;如果不存在任何一条路径,则输出 −1。

输入格式

第一行包含两个整数 N、K。接下来输入 N 行,每行 N 个整数表示棋盘格子上的数字。

输出格式

输出一行表示答案。如果存在答案输出路径,否则输出 −1。

样例输入

3 3
0 2 0
1 1 1
2 0 2

样例输出

41255214

提示

【样例说明】行进路径如图 1 所示。
【评测用例规模与约定】对于 80% 的评测用例:1 ≤ N ≤ 5。对于 100% 的评测用例:1 ≤ N ≤ 10,1 ≤ K ≤ 10。

#include <iostream>
#include<vector>

using namespace std;

int dirss[8][2] = { {-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1} };
bool hash1[11][11][11][11];
bool hash2[11][11];
vector<int> sum;

void dfs(int x, int y, vector<vector<int>>& v, vector<int>& count, int k ,int n)
{
    if (sum.size() > 0) return;

    if (x == v.size() - 1 && y == v.size() - 1)
    {
        if (count.size() == (n*n) - 1)
        {
            sum = count;
        }

        return;
    }

    if (count.size() == (n * n) - 1) return;

    for (int i = 0; i < 8; i++)
    {
        int nx = x + dirss[i][0], ny = y + dirss[i][1];
        if (nx >= 0 && nx < v.size() && ny >= 0 && ny < v.size() && !hash2[nx][ny]&& !hash1[nx][y][x][ny])
        {
            if (v[nx][ny] == v[x][y] + 1 || (v[nx][ny] == 0 && v[x][y] == k - 1))
            {
                hash2[nx][ny] = true;
                hash1[x][y][nx][ny] = true;
                hash1[nx][ny][x][y] = true;
                count.push_back(i);
                dfs(nx, ny, v, count, k,n);
                hash2[nx][ny] = false;
                hash1[x][y][nx][ny] = false;
                hash1[nx][ny][x][y] = false;
                count.pop_back();
            }
        }
    }
}
int main()
{
    int n, k;
    cin >> n >> k;
    vector<vector<int>> v(n, vector<int>(n));
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            cin >> v[i][j];

    vector<int> count;
    hash1[0][0][0][0] = true;
    hash2[0][0] = true;
    dfs(0, 0, v, count, k, n);

    if (sum.size() == 0) cout << -1;

    for (int i = 0; i < sum.size(); i++)
    {
        cout << sum[i];
    }

    return 0;
}

这道题用的是dfs,如何判断是否交叉,只需要关注斜线是否交叉即可,横竖线不可能存在交叉,斜线交叉的坐标画图即可理解

试题G:爬山

小明这天在参加公司团建,团建项目是爬山。在 x 轴上从左到右一共有 n座山,第 i 座山的高度为 hi。他们需要从左到右依次爬过所有的山,需要花费的体力值为 S = Σni=1hi。

然而小明偷偷学了魔法,可以降低一些山的高度。他掌握两种魔法,第一种魔法可以将高度为 H 的山的高度变为 ⌊√H⌋,可以使用 P 次;第二种魔法可以将高度为 H 的山的高度变为 ⌊H/2⌋,可以使用 Q 次。并且对于每座山可以按任意顺序多次释放这两种魔法。

小明想合理规划在哪些山使用魔法,使得爬山花费的体力值最少。请问最优情况下需要花费的体力值是多少?

输入格式

输入共两行。

第一行为三个整数 n,P,Q。

第二行为 n 个整数 h1,h2,. . . ,hn。

输出格式

输出共一行,一个整数代表答案。

样例输入

4 1 1
4 5 6 49

样例输出

18

提示

【样例说明】将第四座山变为 ⌊√49⌋ = 7,然后再将第四座山变为 ⌊7/2⌋ = 3。体力值为 4 + 5 + 6 + 3 = 18。

【评测用例规模与约定】

对于 20% 的评测用例,保证 n ≤ 8,P = 0。

对于 100% 的评测用例,保证 n ≤ 100000,0 ≤ P ≤ n,0 ≤ Q ≤ n,0 ≤ hi ≤ 100000。

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

using namespace std;

int main()
{
    int n, p, q;
    cin >> n >> p >> q;
    priority_queue<int> qq;
    for (int i = 0; i < n; i++)
    {
        int x;
        cin >> x;
        qq.push(x);
    }

    while (p > 0 || q > 0)
    {
        int y = qq.top();
        qq.pop();
        if (y > 4 && p > 0)
        {
            y = sqrt(y);
            qq.push(y);
            p--;
        }
        else if (y > 4 && p == 0)
        {
            y = y / 2;
            qq.push(y);
            q--;
        }
        else if (y < 4 && q > 0)
        {
            y = y / 2;
            qq.push(y);
            q--;
        }
        else
        {
            y = sqrt(y);
            qq.push(y);
            p--;
        }  
    }
    int sum = 0;
    while (!qq.empty())
    {
        sum += qq.top();
        qq.pop();
    }
    cout << sum;
    return 0;
}

试题H:拔河

题目描述

小明是学校里的一名老师,他带的班级共有 n 名同学,第 i 名同学力量值为 ai。在闲暇之余,小明决定在班级里组织一场拔河比赛。

为了保证比赛的双方实力尽可能相近,需要在这 n 名同学中挑选出两个队伍,队伍内的同学编号连续:{al1, al1+1, ..., ar1−1, ar1} 和 {al2, al2+1, ..., ar2−1, ar2},其中 l1 ≤ r1 < l2 ≤ r2。

两个队伍的人数不必相同,但是需要让队伍内的同学们的力量值之和尽可能相近。请计算出力量值之和差距最小的挑选队伍的方式。

输入格式

输入共两行。

第一行为一个正整数 n。

第二行为 n 个正整数 ai。

输出格式

输出共一行,一个非负整数,表示两个队伍力量值之和的最小差距。

样例输入

5
10 9 8 12 14

样例输出

1
#include <iostream>
#include<vector>
#include <cmath>
#include <queue>
#include<algorithm>
#include <set>

using namespace std;

typedef long long ll;
int main()
{
    int n;
    cin >> n;
    vector<long long> v(n+1);
    vector<long long> sum(n+1);
    multiset<ll> S;
    ll mindiff = 9999999999;
    for (int i = 1; i <= n; i++)
    {
        cin >> v[i];
        sum[i] = sum[i - 1] + v[i];
    }

    for (int i = 1; i <= n; i++)
    {
        for (int j = i + 1; j <= n; j++)
        {
            S.insert(sum[j] - sum[i]);
        }
    }

    for (int i = 1; i <= n; i++)
    {
        for (int j = 0; j < i; j++)
        {
            ll x = sum[i] - sum[j];
            auto it = S.lower_bound(x);
            if (it != S.end())
            {
                mindiff = min(mindiff, abs(*it - x));
            }
            if (it != S.begin())
            {
                it--;
                mindiff = min(mindiff, abs(*it - x));
            }
        }
        for (int i2 = i + 1; i2 <= n; i2++)
        {
            S.erase(S.find(sum[i2] - sum[i]));
        }
    }
    cout << mindiff;
    return 0;
}

这道题目用的是前缀和以及二分查找算法,使用multiset存储各个区间的和,然后进行判断

这道题有两个重点

1.循环顺序

2.删除重复数据

这样能够防止区间出现重叠/交叉问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值