洛谷 P1010 [NOIP1998 普及组] 幂次方

文章讲述了如何通过递归方法将正整数表示为2的幂次方形式,通过二进制转换和分析1的位置来逐步拆分,最终得到符合约定的表示。难度较低,涉及基础的算法知识。
摘要由CSDN通过智能技术生成

本文由Jzwalliser原创,发布在CSDN平台上,遵循CC 4.0 BY-SA协议。
因此,若需转载/引用本文,请注明作者并附原文链接,且禁止删除/修改本段文字。
违者必究,谢谢配合。
个人主页:blog.csdn.net/jzwalliser

题目

洛谷 P1010 [NOIP1998 普及组] 幂次方

[NOIP1998 普及组] 幂次方

题目描述

任何一个正整数都可以用 2 2 2 的幂次方表示。例如 137 = 2 7 + 2 3 + 2 0 137=2^7+2^3+2^0 137=27+23+20

同时约定次方用括号来表示,即 a b a^b ab 可表示为 a ( b ) a(b) a(b)

由此可知, 137 137 137 可表示为 2 ( 7 ) + 2 ( 3 ) + 2 ( 0 ) 2(7)+2(3)+2(0) 2(7)+2(3)+2(0)

进一步:

7 = 2 2 + 2 + 2 0 7= 2^2+2+2^0 7=22+2+20 ( 2 1 2^1 21 2 2 2 表示),并且 3 = 2 + 2 0 3=2+2^0 3=2+20

所以最后 137 137 137 可表示为 2 ( 2 ( 2 ) + 2 + 2 ( 0 ) ) + 2 ( 2 + 2 ( 0 ) ) + 2 ( 0 ) 2(2(2)+2+2(0))+2(2+2(0))+2(0) 2(2(2)+2+2(0))+2(2+2(0))+2(0)

又如 1315 = 2 10 + 2 8 + 2 5 + 2 + 1 1315=2^{10} +2^8 +2^5 +2+1 1315=210+28+25+2+1

所以 1315 1315 1315 最后可表示为 2 ( 2 ( 2 + 2 ( 0 ) ) + 2 ) + 2 ( 2 ( 2 + 2 ( 0 ) ) ) + 2 ( 2 ( 2 ) + 2 ( 0 ) ) + 2 + 2 ( 0 ) 2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0) 2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)

输入格式

一行一个正整数 n n n

输出格式

符合约定的 n n n 0 , 2 0, 2 0,2 表示(在表示中不能有空格)。

样例 #1

样例输入 #1
1315
样例输出 #1
2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)

提示

【数据范围】

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 2 × 10 4 1 \le n \le 2\times {10}^4 1n2×104

NOIP1998 普及组 第三题

想法

虽然题目确实写得很清楚了,但是可以梳理一下这个过程。一起理解一下题目吧。以 137 137 137为例,有以下过程:
137 = 2 7 + 2 3 + 2 0 = 2 2 2 + 2 + 2 0 + 2 3 + 2 0 = 2 2 2 + 2 + 2 0 + 2 2 + 2 0 + 2 0 137=2^7+2^3+2^0=2^{2^2+2+2^0}+2^3+2^0=2^{2^2+2+2^0}+2^{2+2^0}+2^0 137=27+23+20=222+2+20+23+20=222+2+20+22+20+20
所以嘛,数字 137 137 137最后表示为了 2 ( 2 ( 2 ) + 2 + 2 ( 0 ) ) + 2 ( 2 + 2 ( 0 ) ) + 2 ( 0 ) 2(2(2)+2+2(0))+2(2+2(0))+2(0) 2(2(2)+2+2(0))+2(2+2(0))+2(0)
像这样的题目,一定是会想到写一个递归函数来处理这样的问题,这是最重要的。当然,本题也考察了数字转化为二进制。

实现

  1. 将数字转化为二进制。
  2. 拆分二进制,找出二进制中 1 1 1所在的位置。
  3. 递归重复以上过程,直到将数字拆分得只剩下 2 2 2 0 0 0
  4. 输出。

题解

C++

#include<bits/stdc++.h>
using namespace std;
string to_bin(int n){ //将十进制转换为2进制
    string digit = "01"; //位
    if(n == 0){
        return "";
    }
    return to_bin(n / 2) + digit[n % 2];
}

vector<int> getbits(int n){ //获取二进制中1所在的位置
    string m = to_bin(n); //获取二进制
    reverse(m.begin(),m.end()); //反转,方便一会儿的遍历
    vector<int> bits; //建列表
    for(int i = 0;i < m.size();i++){ //遍历
        if(m[i] == '1'){ //找到二进制中1的位置
            bits.push_back(i); //记录下来
        }
    }
    return bits; //返回
}

string split(int x){ //递归将数字拆分为只有2和0的形式
    vector<int> bits = getbits(x); //获取1所在的位置
    reverse(bits.begin(),bits.end()); //反转,低位先遍历,高位后遍历
    string str = ""; //记录
    for(int i = 0;i < bits.size();i++){
        str += '2'; //无论如何先整一个2上去
        if(bits[i] > 2){ //如果当前的位大于2
            str += '(' + split(bits[i]) + ')'; //那么需要拆
        }
        else if(bits[i] == 2){ //如果等于2
            str += "(2)"; //那就加个2
        }
        
        else if(bits[i] == 0){ //如果等于0
                str += "(0)"; //那就加个0
        }
        str += "+"; //记得放上加号
    }
    
    return str.substr(0,str.size() - 1); //因为在前面的处理中会导致字符串末尾有一个冗余的加号,所以需要去掉
}


int main(){
    int num;
    cin >> num; //输入
    cout << split(num); //输出
    return 0;
}

Python

num = int(input()) #输入
def to_bin(n): #将十进制转换为2进制
    digit = "01" #获取二进制
    if n == 0:
        return ""
    return to_bin(int(n / 2)) + digit[n % 2]

def getbits(n):
    m = to_bin(n)[::-1] #反转,方便一会儿的遍历
    bits = [] #建列表
    for i in range(len(m)): #遍历
        if m[i] == "1": #找到二进制中1的位置
            bits.append(i) #记录下来
    return bits #返回

def split(x): #递归将数字拆分为只有2和0的形式
    bits = getbits(x) #获取1所在的位置
    string  = "" #记录
    for i in reversed(bits): #反转,低位先遍历,高位后遍历
        string += "2" #无论如何先整一个2上去
        if i > 2: #如果当前的位大于2
            string += "(" + split(i) + ")" #那么需要拆
        elif i == 2: #如果等于2
            string += "(2)" #那就加个2
        elif i == 0: #如果等于0
            string += "(0)" #那就加个0
        string += "+" #记得放上加号
    return string[:-1] #因为在前面的处理中会导致字符串末尾有一个冗余的加号,所以需要去掉

print(split(num)) #输出

难度

难度:★★☆☆☆
大概是没什么难度吧。主要是二进制和递归。其它迎刃而解。

结尾

欢迎Hack我的代码!记得评论区域留言哦!我们下期再见(˵¯͒〰¯͒˵)

  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值