当前位置: 首页 > news >正文

蓝桥杯第十二届省赛B组C++真题解析

蓝桥杯第十二届省赛B组C++真题解析

一、空间(填空题)

​题目链接​​:https://www.lanqiao.cn/problems/1445/learning/
​解题思路​​:

  • 进制转换关系:
    • 1 MB = 1024 KB
    • 1 KB = 1024 B
    • 1 B = 4 字节
    • 1 字节 = 8 比特(bit)
      ​关键公式​​:
      总比特数 = 内存大小(MB) × 1024 × 1024 × 4 × 8

二、卡片(填空题)

​题目链接​​:https://www.lanqiao.cn/problems/2383/learning/
​解题思路​​:

  1. k 张卡片中选两张的不同组合数:
    C ( k , 2 ) = k ( k − 1 ) 2 C(k, 2) = \frac{k(k-1)}{2} C(k,2)=2k(k1)
  2. 选两张相同卡片的组合数:直接取 k 种。
  3. 使用二分法找到最小的 k,满足:
    k ( k + 1 ) 2 ≥ n \frac{k(k+1)}{2} \geq n 2k(k+1)n
    ​代码实现​​:
#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;
    int l = 0, r = n + 1;
    while (l < r) {
        long long mid = (l + r) >> 1; // 防止溢出
        if (mid * mid + mid >= 2 * n) r = mid;
        else l = mid + 1;
    }
    cout << l;
    return 0;
}

三、直线(填空题)

​题目链接​​:https://www.lanqiao.cn/problems/1449/learning/

解题思路

  1. ​遍历所有点对​​:
    • 计算两点间的斜率 k 和截距 b
    • ​注意​​:为避免精度丢失,直接使用代数公式计算 b
      b = x 1 y 2 − x 2 y 1 x 1 − x 2 b = \frac{x_1 y_2 - x_2 y_1}{x_1 - x_2} b=x1x2x1y2x2y1
  2. ​去重方法​​:
    • 使用 set<pair<double, double>> 存储直线参数,自动去重。
    • 垂直直线(x = c)需单独统计,共 ​​20 条​​。

代码实现

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

set<pair<double, double>> lines;

int main() {
    for (int x1 = 0; x1 < 20; x1++) {
        for (int y1 = 0; y1 < 21; y1++) {
            for (int x2 = 0; x2 < 20; x2++) {
                for (int y2 = 0; y2 < 21; y2++) {
                    if (x1 == x2) continue; // 跳过垂直线
                    double k = (double)(y2 - y1) / (x2 - x1);
                    double b = (double)(x1*y2 - x2*y1) / (x1 - x2); // 避免用 k 计算 b
                    lines.insert({k, b});
                }
            }
        }
    }
    cout << lines.size() + 20; // 加上垂直线数量
    return 0;
}

四、货物摆放(填空题)

​题目链接​​:https://www.lanqiao.cn/problems/1463/learning/

解题思路

方法一:暴力法
  1. ​暴力遍历​​:
    • 三重循环遍历所有可能的因子组合 (i, j, k)
    • 计算 i * j * k == n 的组合数。
    • ​缺点​​:复杂度极高,存在大量无效计算。
方法二:因子分解法(优化)
  1. ​因子预处理​​:
    • 遍历 isqrt(n),收集 n 的所有因子。
    • 因子成对存储(in/i),避免重复。
  2. ​组合遍历​​:
    • 三重循环遍历所有因子组合 (a, b, c)
    • 统计满足 a * b * c == n 的有效组合数。
  3. ​复杂度优化​​:
    • 时间复杂度从 O(n^3) 降低到 O(m^3)m 为因子总数)。

关键公式

因子分解 :   ∀ i ∈ [ 1 , n ] ,  if  n m o d    i = 0 ⇒ 保存  i  和  n / i \text{因子分解}:\ \forall i \in [1, \sqrt{n}],\ \text{if}\ n \mod i = 0 \Rightarrow \text{保存}\ i\ \text{和}\ n/i 因子分解: i[1,n ], if nmodi=0保存 i  n/i

代码实现

#include <bits/stdc++.h>
using namespace std;
vector<long long> disvide;//开long long,有因子很大
int main()
{
  long long n = 2021041820210418;
  long long ans = 0;

  /*暴力
  for(long long i = 1; i*i*i<=n; i++ ){
    if(n%i==0){
      for(long long j=i; i*j*j<=n; j++){
        if(n/i%j==0){
          long long k = n/i/j;
          if(i==j&&j==k) ans++;
          else if(i==j||j==k||i==k) ans+=3;
          else ans+=6;
        }else continue;
      }
    }
  }*/
  for(long long i=1; i*i<=n;i++){
    if(n%i==0){
      disvide.push_back(i);
      long long k = n/i;
      if(i!=k) disvide.push_back(k);
    } 
  }//存储因子

  for(auto a=disvide.begin(); a!=disvide.end(); a++)
    for(auto b=disvide.begin(); b!=disvide.end(); b++)
      for(auto c=disvide.begin(); c!=disvide.end(); c++)
      {
        if((*a)*(*b)*(*c)==n) ans++;
      }
  cout << ans;
  return 0;
}

注意事项
**​​数据类型​​:**必须使用 long long 避免大数溢出。
**​​因子去重​​:**当 i 是 n 的平方根时,仅存储一次。
​​性能分析​​:**实测因子数量约为 ​​200​​ 个,总循环次数为 200^3 = 8,000,000,可快速完成。


五、最短路径

​题目链接​​:https://www.lanqiao.cn/problems/1460/learning/

解题思路

动态规划(Dijkstra思想)
  1. ​问题建模​​:

    • 将节点视为图的顶点,边权为两节点的​​最小公倍数(LCM)​​。
    • ​跳跃限制​​:每个节点 i 可跳到 i+1i+21 的节点。
  2. ​状态定义​​:

    • f[j] 表示从节点 1 到节点 j 的最小路径和。
  3. ​状态转移​​:

    • 对每个节点 j,遍历其前驱节点 i(满足 j-21 ≤ i < j)。
    • 更新公式:
      f [ j ] = min ⁡ ( f [ j ] ,   f [ i ] + LCM ( i , j ) ) f[j] = \min(f[j],\ f[i] + \text{LCM}(i, j)) f[j]=min(f[j], f[i]+LCM(i,j))
  4. ​LCM计算​​:
    LCM ( i , j ) = i × j GCD ( i , j ) \text{LCM}(i, j) = \frac{i \times j}{\text{GCD}(i, j)} LCM(i,j)=GCD(i,j)i×j

算法特点
  • ​贪心思想​​:每次用当前最小路径更新后续节点。
  • ​复杂度​​:O(21×n),高效处理大规模节点。

代码实现

#include <iostream>
#include <cstring>  // 包含memset函数
using namespace std;

const int MAX_NODE = 2030;
long long f[MAX_NODE];  // 防止溢出

// 计算最大公约数(非递归实现)
int gcd(int x, int y) {
    while (y != 0) {
        int temp = x % y;
        x = y;
        y = temp;
    }
    return x;
}

int main() {
    // 初始化所有节点为极大值(模拟无穷大)
    memset(f, 0x3f, sizeof(f));
    f[1] = 0;  // 起点路径和为0

    for (int i = 1; i <= 2021; ++i) {
        // 限制跳跃范围:i+1 到 i+21,且不超过2021
        for (int j = i + 1; j <= min(i + 21, 2021); ++j) {
            long long cost = (long long)i * j / gcd(i, j);  // 显式转为long long防溢出
            f[j] = min(f[j], f[i] + cost);  // 关键状态转移
        }
    }

    cout << f[2021] << endl;  // 输出目标节点结果
    return 0;
}

六、时间显示

​题目链接​​:https://www.lanqiao.cn/problems/1452/learning/

解题思路

  1. ​时间单位转换​​:

    • 1 天 = 86400 秒 = 86400000 毫秒
    • 输入毫秒数需先对 86400000 取模,得到当天的剩余毫秒数。
    • 通过整除和取模运算提取小时、分钟和秒:
      • 小时 = 总秒数 / 3600
      • 分钟 = (总秒数 % 3600) / 60
      • 秒 = 总秒数 % 60
  2. ​格式化输出​​:

    • 使用 %02d 格式保证每位数字至少占2位,不足时补前导零。
#include <bits/stdc++.h>
using namespace std;
int main()
{
  string s1;
  long long ms;
  cin >> ms;
  long long t = ms%86400000;
 
  t = ms/1000;
  int s = t%60;
  t /= 60;
  int min = t%60;
	t /= 60;

  if(t%24<10) s1 += '0';
  s1 += to_string(t%24);
  s1 += ":";
  if(min<10) s1 += '0';
  s1 += to_string(min);
  s1 += ":";
  if(s<10) s1 += '0';
  s1 += to_string(s);
  cout << s1;

  return 0;
}

八、双向排序

​题目链接​​:https://www.lanqiao.cn/problems/1458/learning/

解题思路

  1. ​操作分类​​:
    • ​操作类型0​​(降序):对区间 [1, q] 进行降序排序。
    • ​操作类型1​​(升序):对区间 [q, n] 进行升序排序。
  2. ​实现方法​​:
    • 使用 sort 函数直接处理指定区间。
    • sort 的区间参数为​​左闭右开​​(begin, end+1)。

注意事项

⚠️sort函数是左开右闭的区间,默认升序,降序为sort(a,a+n, greater);
⚠️sort(a,a+n,cmp),自定义排序,返回值为bool类型:

bool cmp(int num1, int num2) {
    return num1 > num2;     // 可以简单理解为 > 降序排列;  <  升序排列
}
#include <bits/stdc++.h>
using namespace std;
int a[100010];

int main()
{
  int n,m;
  cin >> n >> m;
  for(int i=1; i<=n; i++) a[i] = i;
  while(m--){
    int p,q;
    scanf("%d %d",&p,&q);

    if(p==0){
      sort(a + 1, a + q + 1,greater<int>());
    }else if(p==1){
      sort(a + q , a + n +1);
    }
  }

  for(int i=1; i<=n; i++) cout << a[i] << " "; 
  return 0;
}

相关文章:

  • 4.7正则表达式
  • el-select组件与el-tree组件结合实现下拉选择树型结构框
  • 深度学习实战电力设备缺陷检测
  • leetcode 416. 分割等和子集 中等
  • 科技快讯 | DeepSeek 公布模型新学习方式;Meta发布开源大模型Llama 4;谷歌推出 Android Auto 14.0 正式版
  • IntelliJ IDEA下开发FPGA
  • 【go】类型断言
  • 学习海康VisionMaster之直线查找组合
  • ResNet改进(22):提升特征选择能力的卷积神经网络SKNet
  • 深入解析 MySQL 底层架构:从存储引擎到查询优化
  • 时序数据库 TDengine × Excel:一份数据,两种效率
  • 借助 AI 工具使用 Python 实现北京市店铺分布地理信息可视化教程
  • Spark,IDEA编写Maven项目
  • 硬盘分区格式之GPT(GUID Partition Table)笔记250406
  • (复看)CExercise_06_1指针和数组_2 给定一个double数组,求平均值,并且返回
  • 第二章:访问远程服务_《凤凰架构:构建可靠的大型分布式系统》
  • React 多个 HOC 嵌套太深,会带来哪些隐患?
  • mac命令操作
  • 在huggingface上制作小demo
  • 初阶C++笔记第一篇:C++基础语法
  • 上海银行副行长汪明履新上海农商银行党委副书记
  • 上海青少年书法学习园开园:少年以巨笔书写《祖国万岁》
  • 持续降雨存在落石风险,贵州黄果树景区水帘洞将封闭至6月初
  • 东航C919航线上新!正式投入上海虹桥—深圳航线运营
  • 山东茌平民企巨头实控人省外再出手:斥资16亿拿下山西一宗探矿权
  • 上海公办小学验证今起开始,下周一和周二分区进行民办摇号