2024蓝桥杯省B好题分析

题解来自洛谷,作为学习

目录

宝石组合

数字接龙

爬山

拔河


宝石组合

# [蓝桥杯 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);                  //开始dfscout << -1;                    //还有种情况是当走不到(n-1,n-1)时,输出-1return 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.xdnf.cn/news/143098.html

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

相关文章

乐vs悲观锁,重vs轻量级锁,公vs非公平锁,不vs可重入锁,等等锁策略

这里讲的“乐观锁”“悲观锁”“轻量级锁”等等&#xff0c;都不是一个锁&#xff0c;而是一类锁。 比如&#xff1a;我们班有“带眼镜”的同学&#xff0c;这里“带眼镜”并不是指一个人&#xff0c;而是指一类人。 并且这里的锁&#xff0c;并不局限于Java&#xff0c;而是只…

优化数据的抓取规则:减少无效请求

在爬取房价信息的过程中&#xff0c;如何有效过滤无效链接、减少冗余请求&#xff0c;是提升数据抓取效率的关键。本文将介绍如何优化爬虫抓取贝壳等二手房平台中的房价、小区信息&#xff0c;并通过代理IP、多线程、User-Agent和Cookies的设置&#xff0c;确保数据抓取的稳定性…

(娱乐)魔改浏览器-任务栏图标右上角加提示徽章

一、目标&#xff1a; windows中&#xff0c;打开chromium&#xff0c;任务栏中会出现一个chromium的图标。我们的目标是给这个图标的右上角&#xff0c;加上"有1条新消息"的小提示图标&#xff0c;也叫徽章(badge)注意&#xff1a;本章节纯属娱乐&#xff0c;有需要…

手脱简单upx

大一下的事情&#xff0c;补个档 手动脱壳の新年快乐 查壳&#xff0c;有壳&#xff0c;UPX X32dbg打开文件&#xff0c;查看初始断点 点击PUSHAD跟进&#xff0c;CTRL*设置EIP&#xff0c;开始F8步过&#xff0c;寻找ESP寄存器第一次单个变红的地址 此时的内存窗口 开始步过…

esp32核心跑分程序

https://github.com/ochrin/coremark/tree/esp32 最近一直捣腾esp32s3 (Sense) 做微型摄像。过程中发现一款不错的跑分软件&#xff0c;特此记一笔。 其中针对esp32s3各类参数设定&#xff08;用idf.py menuconfig)&#xff0c;做个记录。 CPU Frequency去240MHz&#xff08…

【H2O2|全栈】关于CSS(6)CSS基础(五)

目录 CSS基础知识 前言 准备工作 网页项目规范 创建项目 布局 补充一部分属性 outline border-radius 预告和回顾 后话 CSS基础知识 前言 本系列博客将分享层叠样式表&#xff08;CSS&#xff09;有关的知识点。 本期博客主要分享的是网页项目规范&#xff0c;ou…

VC++以资源方式打开可执行文件

刚看一个资料说可以在VC中&#xff0c;以资源方式打开可执行文件&#xff0c;然后它如果包含对话框一些资源&#xff0c;会呈现出来&#xff0c;可以把其他程序界面上的控件直接拷贝到自己程序&#xff1b; 但是操作了一下没有成功&#xff0c; 先新建一个空对话框准备拷贝东…

Linux运维篇-服务器简介

目录 前言服务器分类&#xff08;按服务器的机箱结构来划分&#xff09;台式服务器机架式服务器刀片式服务器 外观部件内部结构前面板前面板组件前面板接口说明前面板指示灯和按钮前面板指示灯/按钮说明 后面板后面板组件后面板接口说明后面板指示灯后面板指示灯说明 主板和 iB…

uni-app生命周期(三)

文章目录 一、uni-app的生命周期二、应用生命周期三、页面的生命周期函数1.简介2.页面加载时序介绍3.页面加载常见问题4.页面加载顺序4.部分生命周期介绍 四、组件的生命周期函数 一、uni-app的生命周期 应用生命周期&#xff08;整个App的生命周期&#xff09; 在app.vue里面…

C++之仿函数和虚函数

仿函数&#xff08;Functor&#xff09;和虚函数&#xff08;Virtual Function&#xff09;是 C 中两个不同的概念&#xff0c;它们在功能和使用场景上有显著的区别。 1. 仿函数&#xff08;Functor&#xff09; 定义&#xff1a; 仿函数&#xff08;也称为函数对象&#xf…

酒店布草洗涤-酒店分层管理编程实现--———未来之窗行业应用跨平台架构

一、添加楼层代码 未来之窗_人工智能_传送阵(添加楼层,客户信息,300,200) CyberWin_Dialog.layer(未来之窗传送,{type:"url",title:title,move:true,width:阵眼宽度"px",height:阵眼高度"px",id:未来之窗app_通用ID,mask:false,align:59,hidecl…

大数据Flink(一百二十一):Flink CDC基本介绍

文章目录 Flink CDC基本介绍 一、什么是CDC 二、CDC的实现机制 三、​​​​​​​​​​​​​​传统 CDC ETL 分析 四、​​​​​​​​​​​​​​基于 Flink CDC 的 ETL 分析 五、​​​​​​​​​​​​​​什么是 Flink CDC 六、​​​​​​​​​​​​​​…

CCF202006_1

问题描述 试题编号&#xff1a;202006-1试题名称&#xff1a;线性分类器时间限制&#xff1a;1.0s内存限制&#xff1a;512.0MB问题描述&#xff1a; 题解&#xff1a; #include<bits/stdc.h>using namespace std; int n, m;struct Node {int x, y;char ch; }node[1010…

51单片机按键数码管(简单设计)

51单片机按键数码管是一个简单的设计项目&#xff0c;使用四位数码管进行显示&#xff0c;矩阵按键加独立按键输入&#xff0c;将读取到据显示在数码管上。 一、参考PCB图 二、参考代码 #include <reg51.h> // LED数码管引脚定义 sbit LED1 P2 ^ 0; sbit LED2 P2 ^ 1;…

spark读取数据性能提升

1. 背景 spark默认的jdbc只会用单task读取数据&#xff0c;读取大数据量时&#xff0c;效率低。 2. 解决方案 根据分区字段&#xff0c;如日期进行划分&#xff0c;增加task数量提升效率。 /*** 返回每个task按时间段划分的过滤语句* param startDate* param endDate* param …

基于Leaflet和天地图的直箭头标绘实战-源码分析

目录 前言 一、Leaflet的特种标绘库 1、特种标绘对象的定义 2、Plot基类定义 3、直线箭头的设计与实现 二、在天地图中进行对象绘制 1、引入天地图资源 2、标绘对象的调用时序 3、实际调用过程 三、总结 前言 在博客中介绍过geoman标绘的具体实现&#xff0c;使用Leaf…

Window Server 2019+ 安装 Docker

刚刚在等待下载的时候&#xff0c;发了篇文&#xff0c;然后发现直接下载docker用不了&#xff0c;看了官网说明发现&#xff1a;Docker 不支持Window Server!!!不要直接下载官网那里的安装包。 那个链接点进去了windows的指南&#xff0c;发现也有问题&#xff0c;给的脚本地…

数据结构:(OJ141)环形列表

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;…

【数据类型】映射map

小明正在备考英语四级考试&#xff0c;但他的词典太厚了&#xff0c;他记不住哪个单词在哪里。 于是他准备开发一个可以直接找某单词在某页的应用。 但是&#xff0c;他不会做&#xff0c;整天十分烦恼。 好啦&#xff0c;进入正题&#xff0c;大家好&#xff0c;我是学霸小羊…

Kubernetes从零到精通(12-Ingress、Gateway API)

Ingress和Gateway API都是Kubernetes中用于管理外部访问集群服务的机制&#xff0c;但它们有不同的设计理念和适用场景。它们的基本原理是通过配置规则&#xff0c;将来自外部的网络流量路由到Kubernetes集群内部的服务上。 Ingress/Gateway API和Service Ingress/Gateway API…