2024蓝桥杯省B好题分析

news2024/9/20 17:31:28

题解来自洛谷,作为学习

目录

宝石组合

数字接龙

爬山

拔河


宝石组合

# [蓝桥杯 2024 省 B] 宝石组合

## 题目描述

在一个神秘的森林里,住着一个小精灵名叫小蓝。有一天,他偶然发现了一个隐藏在树洞里的宝藏,里面装满了闪烁着美丽光芒的宝石。这些宝石都有着不同的颜色和形状,但最引人注目的是它们各自独特的 “闪亮度” 属性。每颗宝石都有一个与生俱来的特殊能力,可以发出不同强度的闪光。小蓝共找到了 $n$ 枚宝石,第 $i$ 枚宝石的 “闪亮度” 属性值为 $H_i$,小蓝将会从这 $n$ 枚宝石中选出三枚进行组合,组合之后的精美程度 $S$ 可以用以下公式来衡量:

$$
S = H_a H_b H_c \cdot \frac{\operatorname{LCM}(H_a, H_b, H_c)}{\operatorname{LCM}(H_a, H_b) \cdot\operatorname{LCM}(H_a, H_c) \operatorname{LCM}(H_b, H_c)}
$$

其中 $\operatorname{LCM}$ 表示的是最小公倍数函数。

小蓝想要使得三枚宝石组合后的精美程度 $S$ 尽可能的高,请你帮他找出精美程度最高的方案。如果存在多个方案 $S$ 值相同,优先选择按照 $H$ 值升序排列后字典序最小的方案。

## 输入格式

第一行一个整数 $n$ 表示宝石个数。  
第二行有 $n$ 个整数 $H_1, H_2, \dots H_n$ 表示每个宝石的闪亮度。

## 输出格式

输出一行包含三个整数表示满足条件的三枚宝石的 “闪亮度”。

## 样例 #1

### 样例输入 #1

```
5
1 2 3 4 9
```

### 样例输出 #1

```
1 2 3
```

## 提示

### 数据规模与约定

- 对 $30\%$ 的数据,$n \leq 100$,$H_i \leq 10^3$。
- 对 $60\%$ 的数据,$n \leq 2 \times 10^3$。
- 对全部的测试数据,保证 $3 \leq n \leq 10^5$,$1 \leq H_i \leq 10^5$。

做题思路

1.找一个 cnt[i]cnt[i] 用于记录从 H1,H2H1​,H2​ 一直到 HnHn​ 中能被 ii 整除的个数。
2.找到最大的 ii 使得 cnt[i]≥3cnt[i]≥3 记为 xx
3.从小到大排序 HH 数组。
4.从 11 到 nn 遍历,判断 Hi∣xHi​∣x ,输出前 3 个满足要求的数。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int h[N],cnt[N];
int main()
{
	int n,x,c=0;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>h[i];
		for(int j=1;j*j<=h[i];j++) {
			if(h[i]%j==0){
				cnt[j]++;
				if(j*j!=h[i]) cnt[h[i]/j]++; 
			}
		}
	}
	for(int i=N-5;i>=1;i--){
		if(cnt[i]>=3){
			x=i;
			break;
		}
	}
	sort(h+1,h+n+1);
	for(int i=1;i<=n;i++){
		if(h[i]%x==0){
			cout<<h[i]<<" ";
			c++;
		}
		if(c==3) return 0;
	}
	return 0;
}

代码思路:

  1. 输入处理
    • 先读取输入,存储每个宝石的“闪亮度”到数组 h 中。
  2. 统计每个公约数的出现次数
    • 代码核心在于使用 cnt[] 数组来统计每个数作为公约数出现的次数。
    • 对每个宝石 h[i],你通过枚举它的每个约数 j 来统计该约数出现的次数。对于约数 j 和对应的商 h[i]/j,都进行计数,这样可以有效统计每个数在所有宝石中的公约数出现的次数。
  3. 找到最多次作为公约数出现的数
    • 在统计完成后,代码从大到小查找第一个至少出现 3 次的公约数(即 cnt[i] >= 3),并将这个数记录为 x
  4. 输出满足条件的 3 个宝石
    • 最后,你对宝石数组 h 进行排序,并输出前 3 个能被 x 整除的宝石。

优点:

  1. 高效的公约数统计

    • 你使用了枚举约数的技巧,对于每个 h[i],你仅需要枚举到 sqrt(h[i]),所以这部分的时间复杂度是较为高效的。总体上,该部分的时间复杂度为 O(n×h[i])O(n \times \sqrt{h[i]})O(n×h[i]​),对于 h[i] 较大的情况可以有效应对。
  2. 贪心的寻找公约数

    • 你从大到小查找第一个至少出现 3 次的公约数,保证了找到的公约数是最大的,从而能够保证美丽度的最大化。
  3. 简洁的实现

    • 代码简洁且逻辑清晰,从输入处理、到统计公约数再到排序输出,结构明了,易于理解。

数字接龙

#include <bits/stdc++.h>
#define pp ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define ll long long
using namespace std;
int n,k;
const int N = 30;
int f[N][N];  
string ans;
bool xie[N][N][N][N],ji[N][N];
int dx[8]={-1,-1,0,1,1,1,0,-1},dy[8]={0,1,1,1,0,-1,-1,-1};    //特别注意要按照题目给的要求来,方便后面直接把i当作八个方向的编号 
void dfs(int a,int b,int c,int zong){              //坐标x,y,数,总步数
    if (a==n-1 && b==n-1 && zong==pow(n,2)-1){     //当走到(n-1,n-1),步数为总格子数减一时(左上角一开始的(0,0)不用走)
        if (ans.empty()) cout << -1;               
        for (int i=0;i<zong;i++) cout << ans[i];
        exit(0);                                   //输出完答案直接关闭程序 
    }
    for (int i=0;i<8;i++){
        int x=dx[i]+a,y=dy[i]+b;
        if(f[x][y]==(c+1)%k){
            if (x>=0 && y>=0 && x<n && y<n && !ji[x][y]){
                int lu=0;                            //用来记录用不用走斜线 
                if (i%2==1){                         //如果走的是斜线需要判断 
                    if(!xie[a][y][x][b]){            //另一条斜线没走过就能走 
                        lu=1;
                        xie[a][b][x][y]=true;        
                        xie[x][y][a][b]=true;
                    }
                    else continue;                   //与其它交叉就跳过这条路 
                }
                ans.push_back(i+'0');
                ji[x][y] = true;
                dfs(x, y,(c+1)%k,zong+1);
                ji[x][y] = false;                    //回溯 
                ans.pop_back();
                if(lu & 1){                          //用到斜线的话需要单独回溯 
                    xie[a][b][x][y]=false;
                    xie[x][y][a][b]=false;
                }
            }
        }
    }
}
int main()
{
    pp;                            //用到dfs怕超时,先关一手 
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n;j++) cin >> f[i][j];
    }
    ji[0][0] = 1;                  //不要忘记左上角是默认走过的 
    dfs(0,0,0,0);                  //开始dfs
    cout << -1;                    //还有种情况是当走不到(n-1,n-1)时,输出-1
    return 0;
}

思路分析:

  1. 基础概念

    • 使用深度优先搜索(DFS)来遍历所有可能的路径。
    • 迷宫是一个 N x N 的棋盘,每个格子里有一个数字。
    • 每一步可以按照八个方向(水平、垂直和对角线)移动到相邻的格子。
    • 在移动时,当前格子中的数字要满足从0到K-1的循环条件,即走到下一个格子的数字必须是 (当前数字 + 1) % K
  2. DFS的递归逻辑

    • 从左上角 (0, 0) 开始,每次移动到符合规则的下一个格子,并且检查这条路径是否可以到达右下角 (n-1, n-1)
    • 记录已经走过的格子,避免重复访问。
    • 对于斜线移动,题目要求两条斜线不能交叉。因此,代码中对斜线的情况进行了特别的处理,用 xie 数组记录是否有交叉的斜线。
  3. 边界条件处理

    • 当遍历到右下角 (n-1, n-1) 并且走过所有格子(步数为 n*n - 1)时,输出路径。
    • 如果尝试了所有可能的路径仍无法找到合法解,则输出 -1

代码详细分析:

  1. 坐标移动方向定义

    • dxdy 数组定义了八个方向,顺序与题目中的顺序保持一致,便于之后直接使用这些方向来移动。
  2. DFS核心部分

    • dfs 函数中,首先判断是否达到了 (n-1, n-1) 并且是否走满了所有格子(总步数为 n*n - 1)。
    • 如果条件满足,输出结果并退出程序。
    • 然后,对八个方向进行尝试移动,确保移动符合条件:格子没有访问过,数字满足条件,且斜线不能与已有斜线交叉。
    • 如果移动成功,继续递归进行深度搜索。搜索完成后进行回溯,恢复状态,以便探索其他可能的路径。
  3. 边界检查

    • 移动过程中对坐标的合法性进行检查,确保不会超出棋盘的边界。
  4. 优化措施

    • 通过 pp 宏定义加快输入输出的速度,避免DFS过程中超时。
    • 一旦找到解,直接退出程序,避免继续多余的计算。

优点:

  1. 思路清晰:代码利用DFS遍历所有可能的路径,并通过条件判断确保每条路径的合法性,思路比较清晰。
  2. 边界处理完备:考虑了各种边界条件,包括边界越界、斜线交叉、数字循环等问题。
  3. 剪枝回溯:利用回溯法在DFS的基础上进行了路径选择和状态恢复,避免了重复计算和死循环。

爬山

贪心思路,分别求出 第一种魔法的结果sqrt_res,第二种魔法的结果div_res,比较谁更小,再决定使用第几种魔法!!!
请特别注意 p == 0 && q != 0、q == 0 && p != 0这两种情况,不需要比较,直接使用有次数的魔法即可。
次数都为0时,跳出while循环

痛哭,比赛的时候紧张,忘记优先队列头文件了,想着for循环遍历一下找最大数很快,没有使用大根堆。

#include<iostream>
#include <queue>
#include <math.h>
using namespace std;
int n,p,q;
priority_queue<int> mount;
int main()
{
    scanf("%d %d %d",&n,&p,&q);
    int t;
    for(int i = 0;i < n;i++)
    {
        scanf("%d",&t);
        mount.emplace(t);
    }
    while(p || q)
    {
        int tmp = mount.top();
        mount.pop();
        int sqrt_res = sqrt(tmp),div_res = tmp / 2;
        if(p)//如果p有次数
        {
            if(q)//如果q也有次数,需要进行比较
            {
                if(sqrt_res <= div_res)
                {
                    mount.emplace(sqrt_res);
                    p--;
                }
            }   
            else//q没有次数,直接emplace,不需要比较
            {
                mount.emplace(sqrt_res);
                p--;
            } 
        }
        else//p没次数
        {
            if(q)
            {
                mount.emplace(div_res);
                q--;
            }
            else//都没有次数,跳出循环
                break;
        }
    }
    long long res = 0;
    while (!mount.empty()) 
    {
        res += mount.top();
        mount.pop();
    }
    cout << res << endl;
    return 0;
}

代码分析:

  1. 数据输入与初始化
    • 首先读取输入的三个参数 npq,然后读取每座山的高度,并将它们依次存入最大堆 mount 中。这个堆会在每次操作时帮助我们迅速找到当前高度最大的山峰。
  2. 主循环:选择和处理最大山峰
    • 你通过 while (p || q) 循环不断处理山峰,直到 p(第一种魔法的次数)或 q(第二种魔法的次数)用完为止。

    • 贪心选择:每次都选出当前最高的山峰,并将其从堆中弹出。然后根据当前的 pq 值,来决定使用哪种魔法。

    • 比较 sqrt_resdiv_res

      • 如果 pq 都有剩余,比较使用两种魔法后的高度,选择效果更好的那个:
        • 第一种魔法将山峰高度开平方,结果为 sqrt_res
        • 第二种魔法将山峰高度除以2,结果为 div_res
      • 如果 sqrt_res <= div_res,则使用第一种魔法,否则使用第二种。
    • 特殊情况

      • 如果 p == 0 && q != 0,则只使用第二种魔法。
      • 如果 q == 0 && p != 0,则只使用第一种魔法。
  3. 结果计算与输出
    • pq 都用完后,程序将剩下的山峰高度全部相加,作为最后的输出结果。

注意点:

  1. 优先队列的使用
    • 使用最大堆是一个非常好的贪心选择。因为每次都需要选择当前高度最高的山峰来操作,这个堆的性质可以确保我们在每次循环中都能快速找到最大值。
  2. 特殊情况处理
    • 代码中处理了 p == 0 && q != 0q == 0 && p != 0 的特殊情况,保证了在一方次数用尽后,不再进行不必要的比较,节省了时间。

拔河

前缀和思想,然后顺便记录每个队伍的区间,以及每个队伍的值,排序后求相邻区间的差值,如果区间没交集则有效,最后输出最小的
#include <bits/stdc++.h>
#define ll long long
#define PLL pair<ll,ll>
using namespace std;
int n;
const int N = 1e3+10;
ll d[N];
ll mi=LLONG_MAX;
struct h{
    ll a;
    int b;
    int c;
};
bool cmp(h x,h y){
    if(x.a==y.a) return x.b<y.b;
    if(x.a==y.a && x.b==y.b) return x.c<y.c;
    return x.a<y.a;
}
int main(){
    vector<h> s;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        ll x;
        scanf("%lld",&x);
        d[i]=d[i-1]+x;
    }
    for(int i=0;i<n;i++){
        for(int k=i+1;k<=n;k++){
            s.push_back({d[k]-d[i],i,k});
        }
    }
    sort(s.begin(),s.end(),cmp);
    for(int i=1;i<s.size();i++){
        if((s[i].b>=s[i-1].c && s[i].c>=s[i-1].c) || (s[i-1].b>=s[i].c && s[i-1].c>=s[i].c))  mi=min(s[i].a-s[i-1].a,mi);
        else{
            for(int j=i+1;j<s.size();j++){
                if((s[i].b>=s[i-1].c && s[i].c>=s[i-1].c) || (s[i-1].b>=s[i].c && s[i-1].c>=s[i].c)){
                    mi=min(s[j].a-s[i].a,mi);
                    break;
                }
                if((s[j].a-s[i].a)>=mi) break;
            }
        }
    }
    printf("%lld",mi);
    return 0;
}

代码分析:

  1. 前缀和的使用

    • 你通过计算前缀和数组 d[] 来快速获得任何区间的和。具体来说,对于区间 [i, k] 的和,可以用 d[k] - d[i] 来得到。这是经典的前缀和技巧,大大减少了重复计算区间和的复杂度。
  2. 区间值的存储

    • 使用结构体 h 来存储每个区间的信息,包括该区间的和 a,区间的起点 b,和终点 c。你将所有的可能区间都存入 vector 容器 s 中。
  3. 排序规则

    • 区间先按区间和 a 进行排序,如果和相同,则按区间起点 b 排序,起点相同再按终点 c 排序。这确保了在相同区间和的情况下,会按照从左到右的区间顺序来排序。
  4. 寻找最小差值

    • 经过排序后,你需要比较相邻的区间和是否有交集:
      • 只有当两个区间的终点和起点没有重叠时,才是有效的两个队伍(两个不相交的区间)。
      • 当发现相邻的两个区间不相交时,计算它们的区间和之差并更新最小差值 mi
  5. 边界处理和优化

    • 代码中包含了一层优化,即在比较两个区间时,如果当前的差值已经大于等于最小差值 mi,则可以提前终止循环,避免不必要的比较。

优点:

  1. 使用前缀和优化区间和的计算:前缀和的使用有效地减少了多次重复的区间和计算,保证了时间复杂度的优化。

  2. 巧妙的排序规则:通过对区间和的排序,并按起点、终点进行二次排序,简化了之后寻找最小差值的过程。

  3. 贪心思想的应用:你通过贪心思想,即优先处理差值较小的区间和,快速找到两个不相交区间的最小差值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2145609.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flutter Android Package调用python

操作步骤 一、创建一个Flutter Package 使用以下指令创建一个Flutter Package flutter create --templateplugin --platformsandroid,ios -a java flutter_package_python 二、修改android/build.gradle文件 在buildscript——>dependencies中添加以下内容 //导入Chaqu…

接口幂等性和并发安全的区别?

目录标题 幂等性并发安全总结 接口幂等性和并发安全是两个不同的概念&#xff0c;虽然它们在设计API时都很重要&#xff0c;但侧重点不同。 幂等性 定义&#xff1a;幂等性指的是无论对接口进行多少次相同的操作&#xff0c;结果都是一致的。例如&#xff0c;HTTP的PUT和DELE…

TON基金会与Curve Finance合作:推出基于TON的新型稳定币互换项目

2024年&#xff0c;TON基金会宣布与去中心化金融&#xff08;DeFi&#xff09;领域的知名协议Curve Finance建立战略合作&#xff0c;携手推出一个全新的基于TON区块链的稳定币交换项目。这一合作标志着TON生态系统在DeFi领域的进一步扩展&#xff0c;并将通过Curve Finance的核…

玖逸云黑系统源码 v1.3.0全解无后门 +搭建教程

功能带有卡密生成和添加黑名单等&#xff0c;反正功能也不是很多具体的自己看程序截图即可。 搭建教程 完成 1.我们先添加一个站点 2.PHP选择7.3 3.上传源码解压 4.导入数据库 5.配置数据库信息config.php 源码下载&#xff1a;https://download.csdn.net/download/m0_6…

Python包管理工具pip 入门

主要参考资料&#xff1a; 全面解析 python 包管理工具 pip: https://blog.csdn.net/maiya_yayaya/article/details/135341026 目录 pypi社区pip工具安装 piprequirements.txt 记录python包管理工具8.1 什么是 requirements.txt8.2 requirements.txt 格式8.3 示例8.4 pip 安装 …

鸿蒙手势交互(二:单一手势)

二、单一手势 有六种&#xff1a;点击手势(TapGesture)、长按手势(LongPressGesture)、拖动手势(PanGesture) 捏合手势(PinchGesture)、旋转手势(RotationGesture)、滑动手势(SwipeGesture) 点击手势(TapGesture) TapGesture(value?:{count?:number, fingers?:number}) /…

7.7opencv中(基于C++) 翻转图像

基本概念 在OpenCV中&#xff0c;翻转图像指的是沿着一个或多个轴翻转图像。OpenCV提供了一个函数 flip 来完成这个任务。这个函数可以沿着水平轴、垂直轴或者同时沿着水平和垂直轴翻转图像。 函数原型 void flip(InputArray src,OutputArray dst,int flipCode );参数说明 •…

vulnhub-prime1

目录 靶场环境解题过程 靶场环境 项目ip靶机&#xff08;prime&#xff09;未知攻击机&#xff08;kali&#xff09;10.128.129.128 解题过程 打开靶机&#xff0c;我们只能看见一个登录界面&#xff0c;上面只有半截提示 我们首先要做的是主机发现&#xff0c;因为是网络适…

使用 HFD 加快 Hugging Face 模型和数据集的下载

Hugging Face 提供了丰富的预训练模型和数据集&#xff0c;而且使用 Hugging Face 提供的 from_pretrained() 方法可以轻松加载它们&#xff0c;但是&#xff0c;模型和数据集文件通常体积庞大&#xff0c;用默认方法下载起来非常花时间。 本文将指导你如何使用 HFD&#xff08…

makefile 的语法(9):函数 file foreach

&#xff08;57&#xff09; 之前学了处理文本的函数&#xff0c;处理文件名的函数&#xff0c;现在学习读取文件的函数 file &#xff1a; &#xff08;58&#xff09;可以对文本中每一项进行函数处理的 foreach &#xff1a; &#xff08;59&#xff09; &#xff08;60&…

路由原理介绍

定义与过程 定义&#xff1a;是指导IP报文发送的路径信息 过程&#xff1a; 检查数据包的目的地确定信息源发现可能的路径选择最佳路径验证和维护路由信息 路由来源 直连路由&#xff1a;不需配置&#xff0c;路由器配置IP后自动生效 静态路由&#xff1a;手动配置 ip r…

小商品市场配电系统安全用电解决方案

1.概述 随着市场经济的快速发展和人民生活水平的不断提高,全国各地相继建起了大批大型小商品批发市场,此类市场以其商品种类繁多、价格实惠、停车方便等特点吸引了大量的顾客,成为人们日常光顾的重要场所,地方便了广大人民群众的日常生活。 小商品市场集商品销售和短时货物储…

分享一个 在线拍卖系统 商品竞拍平台Java、python、php三个技术版本(源码、调试、LW、开题、PPT)

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人 八年开发经验&#xff0c;擅长Java、Python、PHP、.NET、Node.js、Android、微信小程序、爬虫、大数据、机器学习等&#xff0c;大家有这一块的问题可以一起交流&…

【zookeeper安装】zookeeper安装详细教程(单机/集群部署)(linux版)

文章目录 前言一、zookeeper简介二、获取Zookeeper安装包2.1. 离线获取2.2. 在线获取2.3. 解压包 三、单机部署3.1. 配置conf文件3.2. 启动服务 四、集群部署4.1. 概念4.2. 配置conf文件4.3. 创建myid文件4.3. 启动每个节点的zookeeper服务 五、配置systemctl管理&#xff08;选…

neo4j:ubuntu环境下的安装与使用

一、neo4j安装 1. 下载安装包 进入网站&#xff1a;https://neo4j.com/deployment-center/#community 在上图中选择下载即可&#xff08;社区版免费&#xff09; 注意&#xff1a;neo4j的版本要和电脑安装的jdk版本对应&#xff0c;jdk版本使用java --version查看&#xff1a;…

不得不说 Sam‘s Club 的数字化做得挺好

因正好有东西要退货就顺便看了下订单如何退货。 但发现 Sam’s Club 的所有交易都能够从后台查到&#xff0c;同时还提供了个 CSV 文件的下载。 打开下载文件就能看到全部的数字化的交易记录。 就拿加油这个事情来说&#xff0c;能够非常清楚这一年在 Sam’s Club 加油多少加…

【docker】命令之容器操作

一、前言 在上篇博客介绍了关于如何从应用市场&#xff0c;下载镜像后&#xff0c;对镜像的相关操作了。这篇博客呢我们就要讲解我们把镜像下载下来了&#xff0c;启动这个镜像后&#xff0c;就是我们说的容器了&#xff0c;那么容器的具体操作又有那些呢&#xff1f; 二、容器…

基于深度学习的眼部疾病检测识别系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 眼部疾病的早期诊断对于防止视力下降乃至失明至关重要。然而&#xff0c;专业的医疗资源分布不均&#xff0c;尤其是在偏远地区&#xff0c;人们很难获得专业的眼科医生提供的及时诊断服务。本系统…

【devops】devops-gitlab之部署与日常使用

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

XTuner 微调个人小助手认知任务

基础任务 使用 XTuner 微调 InternLM2-Chat-1.8B 实现自己的小助手认知&#xff0c;如下图所示&#xff08;图中的伍鲜同志需替换成自己的昵称&#xff09;&#xff0c;记录复现过程并截图。 创建虚拟环境 在安装 XTuner 之前&#xff0c;我们需要先创建一个虚拟环境。使用 A…