【洛谷2320】【HNOI2006】鬼谷子的钱袋(加强版)
题目背景
鬼谷子非常聪明,正因为这样,他非常繁忙,经常有各诸侯车的特派员前来向他咨询时政。有一天,他在咸阳游历的时候,朋友告诉他在咸阳最大的拍卖行(聚宝商行)将要举行一场拍卖会,其中有一件宝物引起了他极大的兴趣,那就是无字天书。但是,他的行程安排得很满,他已经买好了去邯郸的长途马车票,不巧的是出发时间是在拍卖会快要结束的时候。于是,他决定事先做好准备,将自己的金币数好并用一个个的小钱袋装好,以便在他现有金币的支付能力下,任何数目的金币他都能用这些封闭好的小钱的组合来付账。
题目描述
鬼谷子也是一个非常节俭的人,他想方设法使自己在满足上述要求的前提下,所用的钱袋数最少,并且没有任何两个钱袋装有相等的大于1的金币数。假设他有m个金币,你能猜到他会用多少个钱袋,并且每个钱袋装多少个金币吗?
输入输出格式
输入格式:包含一个整数,表示鬼谷子现有的总的金币数目m。其中,m在long long范围内。
输出格式:两行,第一行一个整数h,表示所用钱袋个数,第二行表示每个钱袋所装的金币个数,由小到大输出,空格隔开。
题解
首先要把题目读懂,即可以用n个1,1个2~m的数,通过加法组合成1~m的所有整数,当然,这所有的数字加起来要等于m,似乎有点复杂,该怎么处理呢?显然,不好直接处理本题,那么先假设一下m=10,如果想要组成1~m的所有整数,那么1是必须要的,因为如果不要1就不能组成1了,然后想,如果有一部分数通过加上一个数等于另外一部分数该多好!那么可以想到把10个数分成1~5和6~10,那么显然,1~5的数字加上5就能够组成6~10,所以取5,然后可以发现这就是不断地求子问题,那么递归,但是5是奇数怎么办?因为c++中的除法向下取整,所以分成1~2,3~5,1~2必须加上3才能组成3~5,那么把3取上,3又分成1和2,3显然1必须加上2才能取2,3,那么取2,因为1是必须取的,所以取1.透过现象看本质,可以发现求解的过程很像倍增,每一次可以取的数目都*2,那么如果2^n > m,那么n即为所求的袋子数,如何求每个袋子装的金币呢?根据之前模拟的过程记录答案即可.通过这道题要明白,一些用字母表示的数不好直接处理,可以设特殊值,从现象看本质,最后想到求解的方法!代码可以缩成1个循环!
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
long long ans[100];
int main(){
long long n,cnt=0;
scanf("%lld",&n);
while(n){
ans[++cnt]=(n+1)/2;
n/=2;
}
printf("%d\n",cnt);
for(int i=cnt;i>=1;i--)
printf("%lld ",ans[i]);
return 0;
}
上一篇: 二分法查找整型有序数组中具体的某个数
下一篇: 二分法实现一个整形有序数组的二分查找