欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 明星 > 【蓝桥杯2024省B】好数 三种解法全解析 | C/C++暴力法→剪枝优化→构造法演进

【蓝桥杯2024省B】好数 三种解法全解析 | C/C++暴力法→剪枝优化→构造法演进

2025/4/18 9:24:44 来源:https://blog.csdn.net/m0_74096349/article/details/147044449  浏览:    关键词:【蓝桥杯2024省B】好数 三种解法全解析 | C/C++暴力法→剪枝优化→构造法演进

好数题解:暴力遍历、剪枝优化与数位构造

点击查看题目

摘要

本文针对「好数」统计问题提出三种递进式解法:暴力遍历通过逐位验证实现简单逻辑;剪枝优化利用个位必为奇数的特性减少50%遍历量;数位构造法采用DFS直接生成合法数字,将时间复杂度优化至指数级。文章提出方法选型指南:小数据(≤1e4)适用暴力法,中等数据(1e4-1e7)推荐剪枝优化,大数据(≥1e7)首选构造法,并探讨了数位DP、并行计算等进阶优化方向,完整呈现算法优化方法论。

题目解析

题目定义 定义满足以下条件的正整数为"好数":

  • 从低位开始计数(个位为第1位)
  • 奇数数位(第1、3、5…位)必须为奇数
  • 偶数数位(第2、4、6…位)必须为偶数

输入输出

  • 输入:正整数N
  • 输出:1到N范围内的好数总数

示例解析

输入#1

24

输出#1

7

解释:符合条件的数字有1,3,5,7,9,21,23

输入#2

2024

输出#2

150


理解题意

根据题目定义,"好数"需满足如下数位特征规律:当数字的某位处于奇数位(即个位为第1位、百位为第3位、万位为第5位等)时,该位数字必须为奇数;当处于偶数位(十位为第2位、千位为第4位、十万位为第6位等)时,该位数字必须为偶数

思路

那么第一个方法是暴力遍历1到n的数字,看看他们符不符合,不过还可以优化,第二种方法是在第一种方法的基础上跳过一些不符合的数字,虽然上面两种方法可以过,但我们不能仅求于此,仍然可以优化,第三个方法就是直接构造符合题意的好数,跳过无关的数字。下面分享我的三种种解法

解法对比

方法时间复杂度优化策略适用场景
暴力遍历O(n·k)N≤1e4
剪枝优化O(n/2·k)跳过偶数遍历N≤1e7
数位构造法O(5^{log₁₀N})合法数字生成N>1e7

当N为最坏情况,N=1e7时:

  • 暴力法:遍历7×1e7次
  • 剪枝优化:遍历7×1e7/2次
  • 构造法:仅需构造5^8=390,625次

方法一:暴力遍历——基础解法

算法思路

  1. 全量遍历:逐个检查1到N的所有数字
  2. 逐位验证
    • 奇数位(个/百/万位)必须为奇数
    • 偶数位(十/千/十万位)必须为偶数

代码

#include<bits/stdc++.h>
using namespace std;
int n;
int ans=0;
bool check(int x)
{int tem = x;int f=0;//0奇1偶while(tem){if(f==0){if(tem%10 % 2 == 0)//奇数位为偶{return false;}}else {if(tem%10 % 2 != 0)//偶数位为奇{return false;}}tem /= 10;if(f==0) f=1;else f=0;}return true;
}
int main() {cin>>n;//遍历判断for(int i=1;i<=n;++i){if(check(i)){ans++;}}cout<<ans;return 0;
}

复杂度分析

  • 时间复杂度:O(n·k)(k为数字平均位数)
  • 空间复杂度:O(1)

方法二:剪枝优化——效率提升50%

优化洞察

个位必为奇数的特性意味着:

  • 所有偶数必然不符合条件
  • 遍历步长可优化为2(仅检查奇数)

代码实现

#include<bits/stdc++.h>
using namespace std;
int n;
int ans=0;
bool check(int x)
{int tem = x;int f=0;//0奇1偶while(tem){if(f==0){if(tem%10 % 2 == 0)//奇数位为偶{return false;}}else {if(tem%10 % 2 != 0)//偶数位为奇{return false;}}tem /= 10;f = 1 - f;//取反操作}return true;
}
int main() {cin>>n;//遍历判断for(int i=1;i<=n;i+=2){if(check(i)){ans++;}}cout<<ans;return 0;
}

性能提升

优化点效果
遍历次数减半时间复杂度降为O(n/2·k)
快速失败机制平均减少20%校验时间

方法三:数位构造法——终极优化

算法思想

采用DFS生成合法数字:

  1. 数位预定义
    • 奇数位候选:{1,3,5,7,9}
    • 偶数位候选:{0,2,4,6,8}
  2. 递归构造
    • 从高位到低位生成数字
    • 及时终止超限分支
  3. 从高位到低位构造数字的原因
    • 每位的可能值是从小到大赋值的,比如奇数位是1,3,5,7,9中轮流赋值
    • 从高位往低位构造,构造的数字才能是严格递增的
    • 如果从低位往高位构造,则不能保证有序,比如65…85…01…21
    • 其实构造顺序不是有序的也是可以的,因为枚举的数字迟早都可以轮到,但如果是递增的话,我们就可以在构造到“>n”的时候停止,因为后面的都是不符合题意范围的,提前停止能提升性能
#include<bits/stdc++.h>
using namespace std;
int n;
int ans=0;//答案
int flag=0;//标记当前构造的数字是否超过n,由于我们构造的数字的顺序是严格递增的,所以超过的时候直接输出答案退出
bool hx[10000005]={0};//判断构造的重复
int fac[10]={0};//存储构造的数字,fac[1]、fac[2]...是构造的数字的个位、十位...
int ji[6]={0,1,3,5,7,9};//奇数位可能的值
int ou[6]={0,0,2,4,6,8};//偶数位可能的值
int is_int(int len)//数组转int函数,len是构造的数字fac数组的长度
{int tem = 0;int f=1;for(int i=1;i<=len;++i){tem += f*fac[i];f *= 10;} return tem;
}
void dfs(int len, int index)//len是总位数,index是当前构造的是第几位,从数字的高位到低位
{//flag为1,即已经构造了大于n的数了,那么后面再构造也是大于n,不符合条件,直接退出if(flag==1) return;//构造完了最低位,可以进行判断if(index == 0)//判断{int gz = is_int(len);//构造的数字大于n,后面也不用遍历了if(gz > n){flag=1;cout<<ans;return ;}else if(hx[gz]==0)//判断是否之前就已经构造过{hx[gz] = 1;ans++;return ;}return ;}//枚举当前位数的可能值for(int i=1;i<=5;++i){//存值if((index)%2 == 1){fac[index] = ji[i];}else{fac[index] = ou[i];}//递归下一位dfs(len, index-1);}
}
int main()
{cin>>n;//题目的n不超过1e7,最大情况是8位数,所以探讨1-8位数的情况即可for(int i=1;i<=8;i++){if(flag == 1) break;dfs(i,i);}return 0;
}

核心机制

机制作用代码体现
动态候选集选择根据位数奇偶自动切换候选数字ji[ ],ou[ ]数组
预判剪枝发现超限立即终止后续构造flag标志
哈希去重避免重复计数hx[ ]数字

算法性能对比

测试环境:洛谷

输入规模暴力法耗时剪枝优化耗时构造法耗时
全部测试点284ms183ms55ms
  • 第一种
    在这里插入图片描述
  • 第二种
    在这里插入图片描述
  • 第三种
    在这里插入图片描述

思维拓展

进阶优化方向

  1. 数位DP优化
    结合动态规划记录中间状态,将时间复杂度优化至O(logN)

  2. 并行计算
    对暴力法进行多线程改造(OpenMP加速):

    #pragma omp parallel for reduction(+:ans)
    for(int i=1;i<=n;i+=2)
    
  3. 数学公式推导
    建立数位长度与可行数的直接关系式,实现O(1)时间复杂度


方法选型指南

场景推荐方法理由
N≤1e4暴力法实现简单,代码量少
1e4<N≤1e7剪枝优化平衡实现难度与性能
N>1e7数位构造法时间复杂度最优
多次查询/预处理构造法+预处理构造结果可缓存复用

竞赛技巧:根据数据规模选择策略,1e7是暴力与构造法的性能分水岭(1s限时最多2*1e7)


总结

三种方法体现了算法优化的典型路径:

  1. 暴力解法:建立问题认知的基础
  2. 剪枝优化:利用问题特性减少无效计算
  3. 构造解法:从根本上重构解题思路

通过这组解法,我们不仅解决了具体问题,更展示了算法优化中"观察特性→减少计算→重构思路"的经典方法论。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词