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 表示(在表示中不能有空格)。
輸入輸出樣例
1315
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}^41≤n≤2×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; }