洛谷P2320 [HNOI2006]鬼谷子的钱袋 题解【数学】【二进制】

作者: wjyyy 分类: 二进制,数学,解题报告 发布时间: 2018-06-21 21:37

点击量:14

 

   这个题是一道数学题,求用现有的钱袋支付所有可支付范围内的最优解。

 

题目描述

鬼谷子非常聪明,正因为这样,他非常繁忙,经常有各诸侯车的特派员前来向他咨询时政。

 

有一天,他在咸阳游历的时候,朋友告诉他在咸阳最大的拍卖行(聚宝商行)将要举行一场拍卖会,其中有一件宝物引起了他极大的兴趣,那就是无字天书。

 

但是,他的行程安排得很满,他已经买好了去邯郸的长途马车票,不巧的是出发时间是在拍卖会快要结束的时候。于是,他决定事先做好准备,将自己的金币数好并用一个个的小钱袋装好,以便在他现有金币的支付能力下,任何数目的金币他都能用这些封闭好的小钱的组合来付账。

 

鬼谷子也是一个非常节俭的人,他想方设法使自己在满足上述要求的前提下,所用的钱袋数最少,并且不有两个钱袋装有相同的大于1的金币数。假设他有m个金币,你能猜到他会用多少个钱袋,并且每个钱袋装多少个金币吗?

 

输入输出格式

输入格式:

包含一个整数,表示鬼谷子现有的总的金币数目m。其中,1≤m ≤1000000000。

 

输出格式:

两行,第一行一个整数h,表示所用钱袋个数

 

第二行表示每个钱袋所装的金币个数,由小到大输出,空格隔开

 

输入输出样例

输入样例#1:
3
输出样例#1:
2
1 2
   很容易联想到,用二进制可以表示所求范围内的所有数。我们把数二进制分解,分为\(2^0,2^1,2^2,…\),对于超出了\(2^n-1\)的范围的那些数,把分解剩下的单独放在一个钱袋里就行了,因为它一定不大于\(2^n-1\)。不过会有特殊情况,就是分解完毕后,得到的最后两袋钱相等,均为\(2^{n-1}\),这样是不合法的,只能让1有多袋。(注意读题)
   为了解决上述问题,我们考虑一个简单的特例:把10分解成1,2,4,4。为了仍能表示\(2^3\)以内的所有数字,我们在替换掉两个4的同时,要拿其它钱袋替换,我们可以用最近的来换,如果换成1,2,3,5,总和不变,在表示8以内的数字时,如果要用到4,就用1和3,如果1要被用掉,我们可以拿5来顶这个4,因此状态是等价的。
   只要对二进制有所了解,这个题的思路是没有障碍的。(再粗心90分也拿到了)

Code:

#include<cstdio>
int ans[100];
int main()
{
    int tot,mx=1,sum=1,cnt=1;
    scanf("%d",&tot);
    ans[cnt]=1;
    tot--;
    while(tot>2*mx)//分解过程
    {
        sum++;
        ans[++cnt]=2*mx;
        tot-=2*mx;
        mx*=2;
    }
    printf("%d\n",sum+1);
    if(tot==mx)
    {
        ans[cnt]--;
        tot++;
    }
    for(int i=1;i<=cnt;i++)
        printf("%d ",ans[i]);
    printf("%d\n",tot);
    return 0;
}

 

说点什么

avatar
  Subscribe  
提醒
/* */