1.倍增法的原理
倍增法顾名思义就是“成倍增长”。那么倍增法只是乘2就了事了吗?对于后缀数组等,有时确实可以简单地乘2。但,大多数题目都可以有更好的解法,那就是利用二进制本身的倍增特性将其展开。如27,27=2^4+2^3+2+1。
任何一个整形n的二进制都只有log2 n位。那么就可以从0快速增长到n,只需要log2 n步。
2.倍增法的例题
【题目描述】任何一个正整数,都可以用2的幂次方来表示,例如:137 = 2^7+2^3+1
在这里,我们约定次方用括号来表示,即a^b
可以表示成a(b)。由上述可知,137又可以表示为:2(7) + 2(3) + 2(0)。进一步可表示为:7 =2^2+2+1= 2(2) + 2 + 2(0) 而 3 = 2 +1= 2 + 2(0)。
所以最后137可以表示为:2(2(2) + 2 + 2(0)) + 2(2 + 2(0)) + 2(0)。又比如:1315 最后可以表示为:2(2(2 + 2(0) +2)) + 2(2(2 + 2(0))) + 2(2(2) + 2(0)) + 2 + 2(0)
【输入】两个正整数m(m ≤ 20000)接下来m行每行输入一个n (n ≤ 100000)
【输出】m行,每行输出相应的n展开后的结果
【样例输入】
2
137
1315
【样例输出】2(2(2) + 2 + 2(0)) + 2(2 + 2(0)) + 2(0)
2(2(2 + 2(0) +2)) + 2(2(2 + 2(0))) + 2(2(2) + 2(0)) + 2 + 2(0)
问题分析:
任何一个满足n=a0*2^0+a1*2^1+a2*2^2+···
其中a0,a1,a2···表示n的二进制的1或0。
如36=2^5+2^2,那么我们只需要知道5和2展开的结果,再将其包在2()中即可
所以递推公式为:如果n是质数则w[n]=2(w[(int)(log2(n))])
否则w[n]=2(w[(int)(log2(n))])+w[i-pow(2,(int)(log2(i)))]
以下是代码的实现
#include<iostream>
#include<cmath>
using namespace std;
#define N 100010
struct node{
string s;
}w[N];
int LOG[N];
void put(int n){
for(int i=0;i<=n;i++){ //也可以提前计算出LOG[N]的值
LOG[i]=LOG[i>>2]+1;
}
}
void init(int n){
for(int i=4;i<=n;i++){
if(!(i&(i-1))){ //i是质数时,做相应处理
w[i].s="2(";
w[i].s+=w[(int)(log2(i))].s;
//等效于w[i].s+=w[LOG[i]].s;
w[i].s+=")";
}else{
//否则加上w[i-pow(2,(int)(log2(i)))].s
//等效于w[i-pow(2,LOG[i])].s
int k=pow(2,(int)(log2(i)));
w[i].s="2(";
w[i].s+=w[(int)(log2(i))].s;
w[i].s+=")+";
w[i].s+=w[i-k].s;
}
}
}
int main(){
int m;
cin>>m;
w[1].s="2(0)";
w[2].s="2";
w[3].s="2+2(0)";
int *a=new int[m];
int maxsize=0;
for(int i=0;i<m;i++){
cin>>a[i];
maxsize=max(maxsize,a[i]);
}
init(maxsize);
for(int i=0;i<m;i++){
cout<<w[a[i]].s;
if(i+1!=m)cout<<endl;
}
return 0;
}
家人们,本宝宝求三连。如有错误请联系本宝宝修改。如有侵权请联系本宝宝删除,谢谢各位的观看。