题解 | 幂次方-牛客假日团队赛8L题
L-幂次方_牛客假日团队赛8
https://ac.nowcoder.com/acm/contest/1069/L
题目描述
任何一个正整数都可以用2的幂次方表示。例如:
同时约定方次用括号来表示,即a可表示为。
由此可知,137可表示为:
进一步:(用表示)
同时约定方次用括号来表示,即a可表示为。
由此可知,137可表示为:
进一步:(用表示)
所以最后可表示为:
又如:
所以最后可表示为:
输入描述:
正整数
输出描述:
符合约定的n的0,2表示(在表示中不能有空格)
示例1
输入
1315
输出
2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)
解答
问题分析:方法一:将n拆分为若干2的幂次方的和,再将各个幂次方(指数)拆分成为若干2的幂次的和……这是递归的思想。递归的边界是什么呢?指数 n=0时候 直接输出2(0),n=1的时候输出 2。如果n>1的时候 那么应该直接输出“2(“,再对指数进行递归,递归后补上括号“)”(类似回溯恢复现场) 整个递归的过程类似于深度优先搜索(DFS)。+号的处理是本题的难点 ,什么时候输出 ‘+’号呢,如果X- 2n不为0,那么说明他剩余部分也需要进行分解的,所以应该需要输出‘+’,例如 那么说明分解了7后 一定要有+号,才能把9部分的分解也加上。
#include<bits/stdc++.h> using namespace std; int x,a[32]; void npow(int n){ for(int i=x;i>=0;--i){ if(a[i]<=n){ n=n-a[i]; if(i>1){ cout<<"2("; npow(i); //可以理解为DFS搜索 cout<<")"; //回溯 } if(i==1) cout<<"2"; if(i==0) cout<<"2(0)"; if(n!=0) cout<<"+"; //若此n还没分解完,则后面还有项,所以输出一个+号 } } } int main() { int n; cin>>n; a[0]=1; while(a[x]<n){ x++; a[x]=a[x-1]*2; } npow(n); cout<<endl; return 0; }
方法二:分治的思想,把一个数X分解为 和进行递归求解,这样可以简单的处理好“+”号的问题。
#include<bits/stdc++.h> using namespace std; string f(int x){ if (x==1) return "2(0)"; if (x==2) return "2"; if (x==3) return "2+2(0)"; //防止3 输出2(2(0))+2(0); int n=log2(x); // 求出指数取整 int t=pow(2, n); if (x==t) return "2("+f(n)+")"; // x 恰好是 2的n次放,后面就没有了 不需要+号。 else return "2("+f(n)+")+"+f(x-t); //不是2的n次方,那么对2部分分别进行递归求解用+号连接 } int main(){ int x; cin>>x; cout<<f(x)<<endl; }
方法三:打表法(作弊)
因为题目中数据规模是 ,所以如果 我们把指数0-14 的表示好放在一个字符串数组里面,如果来了一个数X,我们只需要把对应的幂次方直接输出即可。
#include<bits/stdc++.h> using namespace std; int main() { int n; cin>>n; string s[16]={"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)","2(2(2+2(0))+2(2)+2+2(0))"}; bool temp=0; for(int i=15;i>=0;i--) if(pow(2,i)<=n) { n-=pow(2,i); if(temp) cout<<'+'; cout<<s[i]; temp=1; } return 0; }
来源:qq_37358013