[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 1≤n≤2×104。
NOIP1998 普及组 第三题
题解
这题我怎么看都觉得是记忆化搜索或者动态规划的题,去看题解全是递归?反正对于这道题来说我写不出递归,所以干脆就写dp了。
这题dp思路很简单
137
=
2
7
+
2
3
+
2
0
137 = 2^7 + 2^3 + 2^0
137=27+23+20
其中
7
7
7又可以表示成
7
=
2
2
+
2
+
2
0
7= 2^2+2+2^0
7=22+2+20
这里已经明摆着说我们可以通过动态规划来做这道题,正常思路就是记录由 1 1 1到 137 137 137的所有的解了,可能可以这么解,但我不是这么做的,蒟蒻脑子只能想到这,大佬们轻喷。这里我的做法其实是把所有的 2 2 2的次方给记录下来,什么意思?
我们把 2 0 、 2 1 、 2 2 、 2 3 . . . 2^0、2^1、2^2、2^3... 20、21、22、23...求出来,然后复原数字即可!
状态转移方程为:
d
p
[
t
a
r
g
e
t
]
=
2
(
∑
i
=
0
l
e
n
(
b
i
n
(
t
a
r
g
e
t
)
)
d
p
[
i
]
dp[target] = 2(\sum^{len(bin(target))}_{i=0}{dp[i]}
dp[target]=2(∑i=0len(bin(target))dp[i]
i
f
if
if
b
i
n
(
t
a
r
g
e
t
)
[
i
]
=
=
1
)
bin(target)[i]==1)
bin(target)[i]==1)
看着挺复杂的,其实不复杂, 2 ( ) 2() 2()就是指翻倍,里面的公式指的就是指数对应的值,例如 2 6 = 64 2^6=64 26=64, 6 = 2 2 + 2 6=2^2+2 6=22+2,我们需要去找到 d p [ 2 ] dp[2] dp[2]和 d p [ 1 ] dp[1] dp[1],最后复原 d p [ 6 ] = 2 ( 2 ( 2 ) + 2 ) dp[6] = 2(2(2)+2) dp[6]=2(2(2)+2)
上例就可以这么做,我们求出
d
p
dp
dp(一直求到
d
p
[
7
]
dp[7]
dp[7]):
[
2
(
0
)
,
2
,
2
(
2
)
,
2
(
2
+
2
(
0
)
)
,
2
(
2
(
2
)
)
,
2
(
2
(
2
)
+
2
(
0
)
)
,
2
(
2
(
2
)
+
2
)
,
2
(
2
(
2
)
+
2
+
2
(
0
)
)
]
[2(0), 2, 2(2),2(2+2(0)), 2(2(2)), 2(2(2)+2(0)), 2(2(2)+2), 2(2(2)+2+2(0))]
[2(0),2,2(2),2(2+2(0)),2(2(2)),2(2(2)+2(0)),2(2(2)+2),2(2(2)+2+2(0))]
然后根据二进制为
1
1
1的位置把结果加起来即可
即
137
=
d
p
[
7
]
+
d
p
[
3
]
+
d
p
[
0
]
=
2
(
2
(
2
)
+
2
+
2
(
0
)
)
+
2
(
2
+
2
(
0
)
)
+
2
(
0
)
137 = dp[7] + dp[3] + dp[0] = 2(2(2)+2+2(0))+2(2+2(0))+2(0)
137=dp[7]+dp[3]+dp[0]=2(2(2)+2+2(0))+2(2+2(0))+2(0)
这是不是很简单,^ _ ^
上代码:
Num = int(input().strip())
BNum = bin(Num).replace('0b','')
dp = [str() for _ in range(len(BNum))]
dp[0] = "2(0)"
dp[1] = "2"
def calAns(Bj):
ans = ""
global dp
Bj = Bj[::-1]
for i in range(len(Bj)):
if Bj[i] == "1":
ans = f"{dp[i]}+{ans}" if ans != "" else f"{dp[i]}"
return ans
for j in range(1, len(BNum)):
if dp[j] == "":
Bj = bin(j).replace('0b','')
for i in range(len(Bj)):
if Bj[i] == "1":
dp[j] = f"2({calAns(Bj)})"
ans = calAns(BNum)
print(ans)
因为这道题数据不太行,
数据很小
(
n
<
=
20000
)
(n<=20000)
(n<=20000)由
14
<
l
o
g
2
20000
<
15
14<log_{2}20000<15
14<log220000<15
,我们
d
p
dp
dp其实可以不用求,而是直接写死它!哈哈哈,更简单了:
def Solution2():
Num = int(input().strip())
BNum = bin(Num).replace('0b', '')
dp = ["2(0)", "2", "2(2)", "2(2+2(0))", "2(2(2))", "2(2(2)+2(0))", "2(2(2)+2)", "2(2(2)+2+2(0))", "2(2(2+2(0)))",
"2(2(2+2(0))+2(0))", "2(2(2+2(0))+2)", "2(2(2+2(0))+2+2(0))", "2(2(2+2(0))+2(2))", "2(2(2+2(0))+2(2)+2(0))",
"2(2(2+2(0))+2(2)+2)"]
def calAns(Bj):
ans = ""
Bj = Bj[::-1]
for i in range(len(Bj)):
if Bj[i] == "1":
ans = f"{dp[i]}+{ans}" if ans != "" else f"{dp[i]}"
return ans
print(calAns(BNum))
Solution2()