还是简单题
题意:给定两个数,忽略左右移的情况下,需要几次加减法可以得到他们的乘积。
题解:
对于a*b,可以将a或b转换为二进制并拆解,以b为例
假设b等于21,转换为二进制:10101,则
21
=
2
4
+
2
2
+
2
0
21=2^4+2^2+2^0
21=24+22+20
a
∗
b
=
a
∗
(
2
4
+
2
2
+
2
0
)
=
a
∗
2
4
+
a
∗
2
2
+
a
∗
2
0
=
(
a
<
<
4
)
+
(
a
<
<
2
)
+
(
a
<
<
0
)
a*b=a*(2^4+2^2+2^0)=a*2^4+a*2^2+a*2^0=(a<<4)+(a<<2)+(a<<0)
a∗b=a∗(24+22+20)=a∗24+a∗22+a∗20=(a<<4)+(a<<2)+(a<<0)
所需做的加法次数就是b转换得到的二进制数中1的个数-1
再对a做同样的操作,取小值
但是这并不是最少的操作步骤
比如b等于119,转换为二进制:1110111,
119
=
2
6
+
2
5
+
2
4
+
2
2
+
2
1
+
2
0
119=2^6+2^5+2^4+2^2+2^1+2^0
119=26+25+24+22+21+20,需要做5次加法操作,将连续的1用减法代替:
119
=
2
7
−
2
4
+
2
3
−
2
0
119=2^7-2^4+2^3-2^0
119=27−24+23−20,这样就可以只做3次加减法操作。
将这个方法推广一下就可得到:
2
k
+
2
k
+
1
+
.
.
.
+
2
k
+
n
=
2
k
+
n
+
1
−
2
k
2^k+2^{k+1}+...+2^{k+n}=2^{k+n+1}-2^k
2k+2k+1+...+2k+n=2k+n+1−2k
连续的1都可以转换为1次减法操作
Code:
#include <bits/stdc++.h>
using namespace std;
int an[50];
int slove(int x) {
int res=0,len=0;
while(x) {
an[++len]=x&1;
x/=2;
}
for(int i=1;i<=len;i++) {
if(an[i]==1) {
if(an[i-1]==1) {
an[i-1]=2;
an[i]=-1;
}
if(an[i-1]==-1) an[i]=-1;
}
}
for(int i=1;i<=len;i++) res+=max(0,an[i]);
return res;
}
int main(void) {
int T;
cin>>T;
while(T--) {
int a,b;
cin>>a>>b;
printf("%d\n",min(slove(a),slove(b))-1);
}
return 0;
}