论二进制在题目中的应用

21 篇文章 0 订阅

在开讲之前,首先需要明白下面的一个事实:

任何一个数都能用2的任意次方相加所得。

大家可能也都了解,正是因为它,许多题目都可以用二进制来做,并且大大降低了题目难度,所以二进制的应用我想大家都应该运用的很熟练。

接下来,我们用一个例题来说明二进制的方便可靠:

P2431 正妹吃月饼

题目中给到:

这些月饼的质量分别是 1 g , 2 g , 4 g , 8 g , 16 g . . . . 1g,2g,4g,8g,16g.... 1g,2g,4g,8g,16g.... 后面一个是前面的 2 2 2 倍。每种只有一个。

可以看出,月饼的质量都是 2 2 2 的若干次方,如果从 2 0 2^0 20 开始填
,正好填满显然是最优解,如果不可行的话,就尽量往这方面靠。

题目给出的范围是:对于 100 100 100% 的数据, A , B < = 2 63 − 1 A,B<=2^{63}-1 A,B<=2631,其实这也就告诉我们用二进制做会相对简单,所以我们可以建个容量大于 64 64 64 的数组来存储每一个二进制位的数,并且从小到大来记录,这显然是比从大到小记录简单的,因为月饼重量后一个是前一个的2倍,所以前面的月饼全吃完也没有后面的月饼重,而数量要多得多,这岂不是更划算么?

最后一个需要注意的是,我们每次求出的答案都是从后输入的那个数得来的,它既是 m a x max max

对于样例的解释:
输入 16 16 16 25 25 25

从小的往大的找:

先找 16 16 16的转换,

10000 10000 10000刚好满足。

再找 25 25 25 的 转换,

10001 10001 10001 开始:

10001 10001 10001 从小的往大的找,吃一个 1 g 1g 1g 的,符合;

变成 10011 10011 10011 后还可以再吃一个 2 g 2g 2g 的,符合;

变成 10111 10111 10111 还可以再吃一个 4 g 4g 4g 的,还是符合;

再加一个? 11111 11111 11111,超过了 25 25 25,不符合了,也不用往后找了;

最终答案即为 4 4 4 个,与样例答案一样。

M y My My C o d e Code Code

#include<iostream>
#include<cstdio>
#define MAXN 100
using namespace std;
long long a,b,ma[MAXN],mi[MAXN];
long long t,t_ma=-1,t_mi=-1,u=1;
int main()
{
	scanf("%lld%lld",&a,&b);
	long long bb=b,aa=a;
	//以下两个循环为记录每一位是否进入,一直模2取数,这样就能得到最优解 
	while(a!=0){
		mi[++t_mi]=a%2;
		a/=2;
	}//最小值 
	while(b!=0){
		ma[++t_ma]=b%2;
		b/=2;
	}//最大值 
	for(int i=0;i<64;i++)
		if(mi[i]==1)//记录最小月饼数 
			t++;
	long long v=0;
	while(bb>=aa){//判断月饼的数量是否符合题意 
		if(mi[v]==1)
			v++;//记录 
		else{
			aa+=u;
			t++;
			v++;
		}//没吃的情况 
		u*=2;
	}
	cout<<t-1<<endl;//在while中会重复统计一个已经记录的一个,所以要减一 
	return 0;
}

通过例题,我们不难看出,有了二进制的帮助,我们解题的方法,思路都有了一定的提升,遇到一些特殊的数字,我们就可以想到二进制,从而更好地解决题目。

完结撒花~~

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值