冪次方表達:p1010

2022-11-11 21:00:30

1 題目ID

  P1010 [NOIP1998 普及組] 冪次方

2 題目描述:  

  任何一個正整數都可以用 22 的冪次方表示。例如 137=2^7+2^3+2^0137=27+23+20。

  同時約定方次用括號來表示,即 a^bab 可表示為 a(b)a(b)。

  由此可知,137137 可表示為 2(7)+2(3)+2(0)2(7)+2(3)+2(0)

  進一步:7= 2^2+2+2^07=22+2+20 ( 2^121 用 22 表示),並且 3=2+2^03=2+20。

  所以最後 137137 可表示為 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+11315=210+28+25+2+1。

  所以 13151315 最後可表示為 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)。

輸入格式

  一行一個正整數 nn。

輸出格式

  符合約定的 nn 的 0, 20,2 表示(在表示中不能有空格)。

  輸入輸出樣例

  輸入 #1
  1315
  輸出 #1
  2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)

 說明/提示

  【資料範圍】

  對於 100\%100% 的資料,1 \le n \le 2 \times {10}^41n2×104。

3 題目分析

  輸入一個數位,必然能用 2 的n元次冪和表示(除了0),這是毫無疑問的。但是如何表達?

  首先考慮到每一個數在計算機裡都是按二進位制儲存的,如果將這個數右移一位,這個數就相當於除了2,同時最高位向右移了一位,其位置,相當於最大的2次冪數。

  由此,我們可以得出一個解決方法,對輸入的數進行移位,每移位依次,就輸入對應的狀態的符號,例如輸入7,儲存為 0000 1011。向右移位,得 0000 0101。輸出」2(「,

  再移位,得 0000 0010。輸出 "2)",再移位,得 0000 0001。輸出 "+2" ,再移位,得 0000 0000。輸出 "+2(0)"。以上由遞迴完成。

3.1  資料結構描述

  已知輸入為一位 int 的資料,則為其 二進位制最高位 設定一個 int 型別的狀態位。同時設定一個 string 型別變數,作為輸出。

3.2 演演算法描述

  設定變數  (int) n,作為輸入,設定遞迴函數 op(int x,int i = 0, string s = string("") ) 返回型別為string。x 作為主引數,決定輸出內容。i 作為輔助引數,default為0,用來判斷當前輸出什麼內容,s作為返回引數,default為""。

  將n作為引數輸入op(),進入函數後,首先判斷引數 x 是否為0,若為0,則表明此時當前輸入只能輸出"2(0)"。

  若不為1,判斷是否為0,為0則返回無內容。若不為0,則進入迴圈,若 x 不為 0 ,則往 s 中填內容,若 i 為 1,則表示,此時函數已經遞迴過了,正在判斷是否需要填充2。不為 1,則有兩種可能,一是剛進入函數,二是已多次進入遞迴,之後將 i 作為引數傳入函數op(),進行遞迴。按結果分別往s中填充內容。若 s 填充之前為空,則次數不需要填充"+",因為無內容填充"+",會導致 "(+2"或者"2+)"的情況出現。

  遞迴返回string,輸出函數返回值。

  例如 7 (4 + 2 + 1),7 進入後先表達4,即 2(2)+,2表達為 +2,1表達為 2(0)。最終返回的就是 2(2) + 2 + 2(0)。

4 具體程式碼

  

#include<iostream>
using namespace std;
string op(int x,int i = 0,string s = string("")){
	if(!x)return string("0");
	do 
	   if(x&1)
		  s = (i == 1 ? "2" : "2(" + op(i) + ")") + 
		     (s == "" ? "":"+") + 
  	  	     s;
  	while(++i,x>>=1);
  	return s;
		  
}
int main(){
	int n;
	
	cin>>n;
	
	cout<<op(n)<<endl;
	
	return 0;
}