P1010 [NOIP1998 普及组] 幂次方

该博客详细介绍了如何解决NOIP1998普及组的一个数学问题,即如何将正整数用2的幂次方表示,并遵循特定的括号约定。博主通过递归算法,结合二分查找优化,实现了从给定的正整数n找到满足条件的2的幂次方组合。通过样例和解题思路,展示了具体实现过程和思考过程。
摘要由CSDN通过智能技术生成

[NOIP1998 普及组] 幂次方

题目描述

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

同时约定方次用括号来表示,即 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

解题思路

题目给出数据范围为[1,20000],其中小于2000的2的最高次是14,所以指数的范围为2的[0,14]。
先看题目的例子
137 = 2(7)+2(3)+2(0),

  • 令n等于137,我们可以从 2 14 2^{14} 214开始枚举,直到找到一个可能的最大的可以被n这个数减的数,可以找到 2 7 2^7 27,然后把7放入结果数组。 n = n − n=n- n=n 2 14 2^{14} 214,也就是9
  • n=9时,此时我们可以从上一次的最高次幂7开始枚举,可以找到 2 3 2^3 23可以被n减, n = n − 2 3 n=n-2^3 n=n23,把3放入结果数组,n=1;
  • n=1时,直接把2(0)放入结果数组。
  1. 关于如何处理第一步算出来的指数,我们直接采用递归的方式,把第一步算出来的指数再重新传入函数中,对这个数重新被2的次幂分割即可。

  2. 关于递归的括号怎么加。通过对题目给的1315的样例的观察,我们发现最底层的括号里,也就是加号之间,只有三种可能 2 ( 0 ) 2(0) 2(0), 2 2 2,2(2),所以我们在递归函数中,发现求到的可能最大的指数为 0,1,2时,直接分别返回 2 ( 0 ) 2(0) 2(0), 2 2 2,2(2)即可。如果不为这三种可能,就继续递归。我们在函数传参的过程中传入一个flag=0,表示当前位为本层括号里面的第一个数,那么这个数之前不能有 + ,否则就在前面加一个 +
    3.对于求可能的最大指数的优化。采用二分查找思想,查找满足条件 2 x 2^x 2x不大于n的最大的可能x。(这里的思想和找一个小于n的最大的数的思想一致)。

代码如下

#include<iostream>
#include<algorithm>
#include<cmath> 
using namespace std;
const int maxe = 14;
int binSearch(int l, int h, int n) {
	int re;

	while (l <= h) {
		int mid = (l + h) / 2;
		if (pow(2, mid) <= n) {
			re = mid;
			l = mid + 1;
		}
		else {
			h = mid - 1;
		}

	}
	return re;
}
string  func(int n,int flag) {
	string re;

	while (n > 0) {
		if (flag == 1)
			re += "+";
		int tmpmax = 0;
		if (n > 1) {
			tmpmax = binSearch(0, maxe, n);
			n = n - pow(2, tmpmax);
		}
		else {//n==1时,n=2^0;
			n--;
		}
		
		if (tmpmax == 0) {
		
			re += "2(0)";
		}
		else if (tmpmax == 1) {
			re += "2";

		}
		else if (tmpmax == 2) {
			re += "2(2)";
		}
		else re += "2("+func(tmpmax,0)+")";
		flag = 1;
	}
	
	return re;
	

}
int main() {
	int n;
	
	cin >> n;
	string re=func(n,0);
	cout << re;
}

写在最后

一次过,欧耶!!!感觉自己对于递归的理解又深了一点点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值