第15届蓝桥杯b组省个人赛题解

A 握手问题

在这里插入图片描述

1204

B 小球反弹

在这里插入图片描述
设x速度是15,y速度是17;
这里直接令 vx = dx的值,vy = dy
设x轴上走了p个来回,y轴上走了q个来回
小球经过碰撞回到原点 可得等式
v x ⋅ t = 2 ⋅ p ⋅ x vx \cdot t = 2 \cdot p \cdot x vxt=2px
v y ⋅ t = 2 ⋅ q ⋅ y vy \cdot t = 2 \cdot q \cdot y vyt=2qy
现在知道x,y,可以求出p,q的比值
p q = v x ⋅ y v y ⋅ x \frac{p}{q} = \frac{vx \cdot {y}}{vy \cdot {x}} qp=vyxvxy
知道了比值,我们就可以给p,q赋值计算了

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

const int N = 100010;

// 定义一个求最大公约数的函数
int gcd(int a,int b)
{
    // 使用欧几里得算法
    return b ? gcd(b,a % b) : a;
}

int main()
{
    // 定义两个整数x和y
    int x = 343720 , y = 233333;
    // 定义两个方向dx和dy
    int dx = 15 , dy = 17;
    // 计算p和q,其中p是dx和y的乘积,q是dy和x的乘积
    int p =dx * y, q = dy * x;
    // 使用gcd函数计算p和q的最大公约数d
    int d = gcd(p,q);
    // 将p和q都除以d,得到它们的最简形式
    p /= d;
    q /= d;
    // 输出p和q的最简形式,格式为p/q
    cout << p << "/" << q << endl;
    // 计算t,它是2 * p * x / dx的值
    int   t  =  2  * p * x / dx;
    // 输出t
    cout << t << endl;
    // 计算dist,它是t和sqrt(dx * dx + dy * dy)的乘积
    double dist = t * sqrt(dx * dx + dy * dy);
    // 输出dist,保留两位小数
    printf("%.2f\n",dist);  
    return 0;
}

C 好数

在这里插入图片描述

暴力模拟即可

#include<iostream>
#include<algorithm>
using namespace std;

int cnt = 0; // 初始化计数器为0
void handle(int x) {
    for(int i = 1; i <= x; i++) { // 遍历从1到x的所有整数
        string h = to_string(i); // 将当前整数转换为字符串
        reverse(h.begin(),h.end()); // 反转字符串
        bool flag = true; // 初始化标志位为true
        for(int j = 0; j < h.size(); j++) { // 遍历反转后的字符串的每一位
            int idx = j + 1; // 当前位的索引(从1开始)
            int bit = h[j] - '0'; // 当前位的数字
            if(idx % 2 == 0 ? bit % 2 != 0 : bit % 2 != 1) flag = false;
             // 如果索引是偶数但数字是奇数
            // 或索引是奇数但数字是偶数
            //设置标志位为false
        }
        if(flag) cnt++; // 如果标志位仍为true,计数器加1
    }
}

int main() {
    int x; // 定义输入的整数x
    cin >> x; // 从标准输入读取x
    handle(x); // 调用handle函数处理x
    cout << cnt; // 输出计数器的值
    return 0;
}

D R格式

在这里插入图片描述

模拟即可,注意需要开高精度,如果是时间紧的话可以回头再来开
这里有把小数点忽略然后当成大数来计算,注意最后处理进位的时候
如果进位之后再产生进位,也要进行考虑,比如 99.6 进位之后是 100
所以判断的时候应该写一个循环

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

// 定义乘法函数,将大数A与小数b相乘
vector<int> mul(vector<int> &A, int b) {
    vector<int> C;
    int t = 0;
    for (int i = 0; i < A.size() || t; i++) {
        if (i < A.size()) t += A[i] * b;
        C.push_back(t % 10); // 将结果的每一位添加到C中
        t /= 10; // 处理进位
    }
    while (C.size() > 1 && C.back() == 0) C.pop_back(); // 删除前导零
    return C;
}

int main() {
    int n;
    cin >> n;
    string s;
    cin >> s;
    reverse(s.begin(),s.end()); // 反转字符串,方便处理

    vector<int> num;
    int pos = -1;
    for(int i = 0; i < s.size(); i++) {
        if(s[i] == '.') pos = i - 1; // 记录小数点的位置
        else num.push_back(s[i] - '0'); // 将数字添加到num中
    }

    while(n--) num = mul(num, 2); // 执行乘法操作
    int k = pos;

    if(pos != -1) {
        if(num[pos] >= 5) num[pos + 1]++; // 处理四舍五入
        pos++;
        while(num[pos] >= 10) { // 处理进位
            num[pos] -= 10;
            num[pos + 1]++;
            pos++;
        }
    }

    for(int i = num.size() - 1; i > k; i--) cout << num[i]; // 输出结果
    return 0;
}

E 宝石组合

在这里插入图片描述
根据算数基本定理可以化简
最后化简的S = gcd(ha,hb,hc)

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

const int N=100010;
vector<int> vd[N], cnt[N];
int n;

// 预处理出每个数的约数
void init() {
    for(int i=1; i<=100000; i++)
        for(int j=i; j<=100000; j+=i)
            vd[j].push_back(i);
}

int main() {
    scanf("%d", &n);
    vector<int> a(n+1);
    init(); // 初始化
    for(int i=1; i<=n; i++)
        cin >> a[i];

    // 对数组进行排序
    sort(next(a.begin()), a.end());

    // 对每个数的约数进行计数
    for(int i=1; i<=n; i++)
        for(auto d : vd[a[i]])
            cnt[d].push_back(a[i]);

    // 找出可以作为三个数的最大公约数的数
    int res=0;
    for(int i=N; i>=0; i--) {
        if(cnt[i].size() >= 3) {
            res = i;
            break;
        }
    }

    // 打印出可以被最大公约数整除的前三个数
    for(int i=0; i<3; i++)
        printf("%d ", cnt[res][i]);

    return 0; 
}

F 数字接龙

在这里插入图片描述

简单的搜索,只是多加了几个判断

#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;

typedef long long ll;

#define int long long

const int N = 110;

int n, k;

struct node
{
    int nx;
    int ny;
    int dir;
};

int g[N][N];
bool st[N][N];

int dx[] = { -1,-1,0,1,1,1,0,-1 };
int dy[] = { 0,1,1,1,0,-1,-1,-1 };
vector<int> ans;

void dfs(int sx, int sy, int now, vector<int> path)
{
    if(!ans.empty())return;

    if (sx == n - 1 && sy == n - 1)
    {
        if (path.size() == n * n - 1)
        {
            ans = path;
             
        }
        return;
    }
    now %= k;
    st[sx][sy] = true;  
    for (int i = 0; i < 8; i++)
    {
        int nx = sx + dx[i];
        int ny = sy + dy[i];
        if (nx < 0 || nx >=  n || ny < 0 || ny >= n) continue;
        if (st[nx][ny]) continue;
        if (g[nx][ny] == (now + 1) % k)
        {
            if(i == 0)
            {
                if(st[sx - 1][sy - 1]&&st[sx - 1][sy+1])continue;
            }
            else if (i == 1)
            {
                if (st[sx - 1][sy] && st[sx][sy + 1]) continue;
            }
            else if(i == 2)
            {
                if(st[sx - 1][sy + 1]&&st[sx + 1][sy + 1])continue;
            }
            else if (i == 3)
            {
                if (st[sx + 1][sy] && st[sx][sy + 1]) continue;
            }
            else if (i == 4)
            {
                if (st[sx + 1][sy + 1] && st[sx + 1][sy - 1]) continue;
            }
            else if (i == 5)
            {
                if (st[sx + 1][sy] && st[sx][sy - 1]) continue;
            }
            else if (i == 6)
            {
                if (st[sx - 1][sy - 1] && st[sx + 1][sy - 1]) continue;
            }
            else if (i == 7)
            {
                if (st[sx - 1][sy] && st[sx][sy - 1]) continue;
            }
            st[nx][ny] = true;
            path.push_back(i);
            dfs(nx, ny, (now + 1) % k, path);
            path.pop_back();
            st[nx][ny] = false;


        }
    }

    st[sx][sy] = false; 


    return;





}

signed main()
{
    cin >> n >> k;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            cin >> g[i][j];
        }
    }
    vector<int> path;

    if (g[0][0] != 0) {
        cout << -1 << '\n';
        return 0;
    }
    st[0][0] = true;
    dfs(0, 0, g[0][0],{});
    
    if(ans.size() == 0)
    {
        cout<<"-1"<<endl;
        return 0;
    }
    else{
        for(int i=0;i<ans.size();i++)
        {
            cout<<ans[i];
        }
    }
     
        return 0;
    



    return 0;
}

G 爬山

在这里插入图片描述
很容易就想到优先队列,但是这么写的错误的。
理论上来说最完美的解法就是纯暴力因为实际上是没有规律可循的,所以在这个时间复杂度下
可以说这个题目是无解的
如果是纯暴力的方法,时间复杂度将远超
( p + q ) n {(p+q)}^n (p+q)n

是无解的

贪心方法的错误数据如下
爬山这题有人提出了同差值时优先偶数的做法,以通过以下用例:

2 1 1
48 49

正确方法是 48 开根号 为 6
49 除 2 为 24
最小为30

很可惜,该做法依然是错误的,这是一组反例:

2 1 3
35 36

在这个用例中,你必须先对35开根,然后对36除以二3次。
有人提出了先进行所有开根操作再进行除以二操作,按操作前后差值从大到小贪心进行,差值相同时优先选择较小数开根的做法,但可惜依然是错误的,只需对上述用例稍作修改即可:

2 1 3
35 39

事实上,第二个数取36~39的范围内的任何数,你都必须先对35开根,然后对该数除以二3次。

所以不用深究,直接优先队列就行

#include<iostream>
#include<queue>
#include<math.h>
using namespace std;

priority_queue<int,vector<int>,less<int> >qe;  // 定义一个优先队列

int main()
{
    int n,p,q;
    cin>>n>>p>>q;
    int a;
    for(int i=0;i<n;i++)  // 读入n个数
    {
        cin>>a;
        qe.push(a);  // 将数放入优先队列中
    }
    
    long long sum=0;
    while(p>0||q>0)  // 当p或q大于0时,继续循环
    {
        a=qe.top();  // 取出队列中的最大值
        qe.pop();  // 删除队列中的最大值
        
        if(q==0)  // 如果q等于0,那么只能进行平方根操作
        {
            a=sqrt(a);
            p--;
            qe.push(a);
        }
        else if(p==0)  // 如果p等于0,那么只能进行除以2的操作
        {
            a/=2;
            q--;
            qe.push(a);
        }
        else  // 如果p和q都大于0,那么选择使a变小的操作
        {
            if(fabs(a-a/2)<fabs(a-sqrt(a)))  // 如果除以2后的a比平方根后的a小,那么选择除以2的操作
            {
                a=sqrt(a);
                p--;
                qe.push(a);
            }
            else  // 否则,选择平方根的操作
            {
                a/=2;
                q--;
                qe.push(a);
            }
        }
    }
    
    int n1=qe.size();
    for(int i=0;i<n1;i++)  // 计算队列中所有数的和
    {
        a=qe.top();
        sum+=a;
        qe.pop();
    }
    
    cout<<sum;  // 输出和
    
    return 0;
}

H 拔河

在这里插入图片描述
注意所有人可以不全上
预处理所有前缀和然后暴力即可

#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int>pii;
#define N 10100
int s[N],a[N];
signed main(){    
    int n;
    cin>>n;
    vector<pii>v;
    for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j++){
            v.push_back({s[j]-s[i-1],i});
        }
    }
    sort(v.begin(),v.end());
    int ans=1e18;
     for(int i=0;i<v.size()-1;i++){
         if(v[i].second!=v[i+1].second) ans=min(ans,v[i+1].first-v[i].first);
     }
    cout<<ans<<endl;
    return 0 ;
}

最后附上蓝桥杯题目自测网站

https://www.dotcpp.com/oj/problemset.php?page=89

  • 24
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值