当前位置:首页 > 入门组 > 【NOIP1998】幂次方解题:递归与位运算的巧妙结合(附代码解析)

【NOIP1998】幂次方解题:递归与位运算的巧妙结合(附代码解析)

22小时前

【NOIP1998】幂次方解题:递归与位运算的巧妙结合(附代码解析) 幂次方分解 递归算法 位运算 第1张

一、题目解读

1998年NOIP普及组题目“幂次方”(对应洛谷P1010)要求将给定整数N转换为2的幂次方和的表达式,例如N=5应输出“2+2(2)”。题目考察对数字分解、递归算法位运算的理解,需找到高效的分解方法并生成规范的表达式。

二、解题思路

递归+位运算的策略:

1. 递归分解核心:将整数N分解为多个2的幂次方之和(如N=7 → 2² + 2¹ + 2⁰)。

2. 位运算优化:利用左移运算符(1 << i)快速计算2的i次方,从高位到低位遍历,判断N是否包含当前幂次,若包含则递归处理剩余部分。

3. 表达式拼接:递归调用生成子表达式,按规则添加括号和加号。

三、解题步骤

1. 边界处理:当N=0/1/2时直接返回特殊结果。

2. 分解循环:从2²⁰开始向下遍历,若N≥2ⁱ,则将i加入幂次列表,并更新N减去当前幂次。

3. 递归生成子项:对每个幂次i,若i=1则直接输出“2”,否则递归调用DFS(i)生成子表达式,如“2(2(0))”。

4. 拼接结果:用vector存储幂次,遍历时添加“+”分隔,最后组合成完整表达式。

四、代码与注释

#include <iostream>
#include <string>
#include <vector>
using namespace std;

// 递归函数:将n转换为2的幂次方和表达式
string dfs(int n) {
    if (n == 0) return "0";          // 边界:0直接返回
    if (n == 1) return "2(0)";       // 1的特殊处理
    if (n == 2) return "2";          // 2的特殊处理

    vector<int> powers;              // 存储分解的幂次
    int temp = n;                    // 临时变量记录剩余值

    // 从最高次方开始遍历分解
    for (int i = 20; i >= 0; i--) {
        if (temp >= (1 << i)) {       // 若剩余值≥2ⁱ,加入幂次列表并减去对应值
            powers.push_back(i);
            temp -= (1 << i);
        }
    }

    string res;                      // 结果表达式
    for (int i = 0; i < powers.size(); i++) {
        int p = powers[i];
        if (p == 1) {                // 幂次为1时直接输出"2"
            res += "2";
        } else {                     // 否则递归生成子表达式
            res += "2(" + dfs(p) + ")";
        }
        if (i!= powers.size() - 1) {  // 非最后一个项添加"+"分隔
            res += "+";
        }
    }
    return res;
}

int main() {
    int n;
    cin >> n;                      // 输入整数N
    cout << dfs(n) << endl;        // 输出表达式
    return 0;
}

五、总结

该解法巧妙结合递归与位运算,通过从高位向低位分解,避免了暴力枚举,时间复杂度为O(logN)。递归深度取决于N的二进制位数,而位运算使分解过程简洁高效。代码结构清晰,递归边界与表达式拼接逻辑严谨,是学习递归算法与位运算结合的典型案例。


原创内容 转载请注明出处

分享给朋友:

相关文章

力扣450题:删除二叉搜索树中的节点 - 递归解法详解

力扣450题:删除二叉搜索树中的节点 - 递归解法详解

内容简介本文详细解析了力扣450题"删除二叉搜索树中的节点"的递归解法。通过递归遍历二叉搜索树并根据不同情况处理节点删除操作,实现了BST节点的精确删除。文章包含完整注释代码、算法...

力扣226题:翻转二叉树 - 递归解法详解

力扣226题:翻转二叉树 - 递归解法详解

内容简介本文详细解析了力扣226题"翻转二叉树"的递归解法。通过递归遍历二叉树的每个节点并交换其左右子树,实现了二叉树的完全翻转。文章包含完整注释代码、算法思路讲解和复杂度分析,帮...

【蓝桥杯2015省赛解析】生命之树:树形DP解题全攻略(洛谷P8625代码详解)

【蓝桥杯2015省赛解析】生命之树:树形DP解题全攻略(洛谷P8625代码详解)

一、题目解读    “生命之树”是一道经典的树形结构问题,要求计算一棵带权树中,以某个节点为根的最大子树权值和。题目输入为n个节点及边信息,每个节点有权值wi,...

手搓二叉树构建类代码详解:从入门到实践(适合新手小白)

一、简介和应用二叉树是数据结构中常见的一种树形结构,每个节点最多有两个子节点(左子节点和右子节点)。它广泛应用于算法设计、数据存储与搜索(如二叉搜索树)、表达式解析等领域。本文将通过手写的C++代码,...

洛谷2789题解:直线交点数的递归求解与优化(附代码详解)

洛谷2789题解:直线交点数的递归求解与优化(附代码详解)

一、题目解读洛谷2789题要求计算n条直线在平面上两两相交时产生的不同交点数量。题目强调“不同”交点,需排除重复情况。解题关键在于如何高效枚举所有可能的交点组合,并避免重复计数。二、解题思路参考代码采...

洛谷P3694题解:动态规划与状态压缩优化解题全解析

洛谷P3694题解:动态规划与状态压缩优化解题全解析

一、题目解读洛谷P3694题要求解决一个多团队人数分配问题,给定n个元素和m个团队,每个元素属于一个团队,需将元素重新排列,使相邻元素属于不同团队,并最小化调整次数。题目难点在于如何高效处理团队间的空...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。