中秋特辑—洛谷题目讲解
P2431 正妹吃月饼
又快到了一年一次的中秋节了,也不知道大家有没有去吃月饼,嘿嘿,我最喜欢云腿月饼老好吃了。
虽然是到了中秋节,但是我们依然要刷题来复习和提高自己欸。
现在Bugku都开始发月饼了,嘿嘿但是我们尽头主要是回归一下老本行,今天就进行一次算法题目讲解吧,正好我们可以复习复习一下以前的知识,那么我们就开始吧
今天我们讲解的是
众说周知,洛谷的难度都要往上提一个级别才是这个题目的真正难度。。。咳咳咳好了好了话不多说,我们就开始看题吧
好吧,我的第一感觉就是贪心,模拟。
让我康康我猜的对不对
欸,还有个进制?好吧,,等晚一些我再研究一下为啥会用到进制。
如果不看进制,我想到的第一个思路就是:
1.将所有的月饼克数按照从小到大的顺序相加,加到一个在a和b范围以内的值
2.找到这样一个值以后返回就可以了。
既然有思路我们就先试试看这样写能不能成
#include<iostream>
using namespace std;
int main(){
int sum=1,a,b,ans=2,num=0;
cin>>a>>b;
while(sum<=b){
sum+=ans;
ans*=2;
num++;
}
cout<<num;
return 0;
}
这就是最简单的思路了对吧,看上去也很简单,就是不断乘不断加再不断计数
对于num为啥从0开始其实是因为,虽然一开始我们sum已经是0了但是在最后一次while循环中我们会加上下一个我们不会去吃的月饼就会多一个,如果num从1开始算的话,我们最后输出的num就要减去最后我们没有吃的哪一个月饼,然后我们运行一下尝试一下
好像没啥大问题,那么我们先提交看一下
你看,已提交问题就出来了
其实出现问题是肯定的,毕竟一个简单的模拟不可能在洛谷达到普及+/提高的难度
那咋办啊,我们先找到原因,回到题目
发现问题了,这空间那么大,无法满足。
这个时候我们就想到刚才的进制了,莫非用二进制表示?
那么我们先想一下思路,说到二进制就想到了位运算
因为我们存在了第一个1g月饼的存在,也就是说明我们无论如何吃,要吃多少,都肯定是一个单数,那么单数在二进制如何表达呢,就是最低位肯定为1,并且我们可以从a开始到b中间,我们可以大胆的推测找一下1最多的二进制然后将1的个数统计出来也许就可以了。
好的理论存在,我们就可以开始实践一下了:
我们先进行一下分布实现:
while((a | a+1)<=b){
a |= a+1;
}
这一步主要是找到a和b之间1最多的二进制,下一步
while(a){
ans +=a&1;
a>>=1;
}
统计最多1的二进制中a的个数,ans每统计一次a就右移一位也就是说111就会变成011移动一位之后最右边的1就不在了最左边用0代替也可以省略0
然后结合起来
【因为我对于二进制的了解不多,我运用到的是以前看到过的相似的一个题的写法】
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int ans=0,a,b;
cin>>a>>b;
while((a | a+1)<=b){
a |= a+1;
}
while(a){
ans +=a&1;
a>>=1;
}
cout<<ans;
return 0;
}
芜湖,然后我们尝试运行一下
结果还是一样的,那么我们再提交一下尝试一下
欸~~~~~为啥呀为啥呀。。。。
好吧,我们再理性分析一波,会不会是a和b的值我用Int装不下?
那么我们尝试一下long long
将int a b;
改为 long long a b;
试一下,欸,好像没问题了欸
嘿嘿嘿,你学废了吗,这题其实是有一点难度的,主要是考大家对于二进制的熟悉和写法,还有我们要充分主要到二进制的特点,只有0和1我们就要运用到两个的个数。
不知道大家有啥其他的写法,大家可以一起分享和交流