由于原文的解析过于简单 ( 大佬不说人话) ,此文章在原文的基础上加上了评论与额外的解析,旨在分享自己学习的成果
原文链接:https://blog.csdn.net/qq_45874814/article/details/115185844
小A遇到了一座神奇的泉水,在泉水中洗涤会大幅增加他的精力。在一次洗涤中,泉水增加力量的数值为当前力量二进制表示中的最低位的1对应的值。
例如:
如果当前力量为9(1001 最低位1对应的值为1),增加的力量为1;
如果当前力量为12(1100 最低位1对应的值为100),增加的力量为4。
小A想要将他的力量变为2的幂次数,他需要在泉水中洗涤多少次呢?
多样例测试
第一行输入T(T<=100,000),代表样例数;
剩余T行,每行输入一个数n(n<1,000,000,000)代表小A当前的力量。
对于每次询问,输出小A需要在泉水中洗涤的次数。
4
1
2
3
5
0
0
1
2
#include
using namespace std;
typedef long long ll;
int jud(ll n){
int ans = 0;
while(n > 1){
if(n%2 == 1){
ans++; n++; n=n/2;
}else n = n/2;
}
return ans;
}
int main(){
ll t, a;
scanf("%lld",&t);
while(t--){
scanf("%lld",&a);
printf("%d\n",jud(a));
}
}
解析:
这首先要对题目进行数学分析,但我数学不好,对二进制不够熟悉,所以这一题没有做出来。(这就是强者的世界吗?)
jud函数就是这个程序的精髓,大佬已经参破这一题的要点了。
废话结束,开始分析:
如果你想让一个数变为2的幂次数,最好的方法就是把它转化二进制,这样便于观察与操作。
按照题目的思路,我们尝试做一下题目
9的二进制数为1001,假设这是小A的力量。
洗一次后,他的力量为10,即为1010,
再洗一次,他的力量为12,即为1100,
再来一次,他的力量为16,即为10000.
结果为3
我想,聪明的你已经看破了这道题的本质了。
如果还是不懂的话,我再来举个例子
假设小A的力量为41,二进制为101001,
洗一次后,他的力量为42,即为101010,
再洗一次,他的力量为44,即为101100,
接下来是48,即11000,
最后,是64,即100000.
结果为4
到这里,如果还是不懂的话,咱们来看看这个题二进制计算的规律:
以41为例,它的二进制为101001,末尾不是0,加一,1;
101010,末尾是0,砍去0,得10101,加一得10110,2;
10110,末尾是0,砍去0,得1011,加一得1100,3;
1100。末尾是0,砍去所有1后面的0,得11,加一得100,4;
至此,计算完毕。
好,我们现在知道了这个题的解法,那么接下来,我们只需要将得到的算法转变为代码就可以了。
这里只需要注意:二进制中的砍去末尾的“0”的操作就是在十进制中除2的操作,进行每次加一操作就是在模拟一次洗泉水,输出加一得次数即为结果
这下看大佬的jud函数就可以知道,大佬的算法有多精妙了,题目也迎刃而解。