TIitle

P1010 [NOIP1998 普及组] 幂次方

题目描述

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

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

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

进一步:

7= 2^2 +2+2^0 ( 2^1 用 2 表示),并且 3 = 2+2^0。

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

又如 1315=2^10 +2^8 +2^5 +2+1

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

输入格式

一行一个正整数 n。

输出格式

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

样例

样例输入

1315

样例输出

2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)

Link

[P1010 NOIP1998 普及组] 幂次方 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Ideals

步骤

这道题属于比较明显的递归,大致上步骤分两步:

  1. 把大整数分解成2的幂乘相加的形式,如11 = 2(3)+2(1)+2(0)
  2. 把大整数下的小整数继续划分,结果是11 = 2(2+2(0))+2+2(0)

思路

  1. 把大整数分解成2的幂乘相加的形式,这个可以用二进制来实现,二进制字符串中1对应的下标可以算出幂乘的数字
  2. 例如:11的二进制为1011,1对应的幂乘数字为3、1、0,不难得出 len - 1 - i的计算方法。
  3. 也就是说这里我们可以输出11 = 2(3)+2(1)+2(0)的格式了,但是有一个比较烦的是加号的输出,这里用了一个标记sign,sign初始为0,也就是第一次不输出加号,第一次进入for就把sign置为1,后面每次都输出+2()的格式。
  4. 接下来把小整数丢进递归,也就是执行devide( len - 1 - i)。
  5. 细节1是递归出口是0、1、2,细节2是输出1的时候不要加括号,即不要输出2(1),只输出2。所以加了这句if len(b) - 1 - i != 1,是1就不打括号。

Code

def devide(num):
    sign = 0
    if num == 1:
        return
    elif num <= 2:
        print(num,end='')
    else:
        b = bin(num)[2:]
        for i,c in enumerate(b):
            if c == '1':
                if sign == 0:
                    sign = 1
                else:
                    print("+",end='')
                print("2",end='')
                if len(b) - 1 - i != 1:
                    print("(",end='')
                devide(len(b) - 1 - i)
                if len(b) - 1 - i != 1:
                    print(")",end='')

if __name__ == '__main__':

    devide(int(input()))

Analyse

这道题属于递归,递归的复杂度算起来比较麻烦,这里可以猜测复杂度是O(logn)