1. 程式人生 > >P2320 [HNOI2006]鬼谷子的錢袋(分治思想,水題)

P2320 [HNOI2006]鬼谷子的錢袋(分治思想,水題)

題目描述
鬼谷子非常聰明,正因為這樣,他非常繁忙,經常有各諸侯車的特派員前來向他諮詢時政。

有一天,他在咸陽遊歷的時候,朋友告訴他在咸陽最大的拍賣行(聚寶商行)將要舉行一場拍賣會,其中有一件寶物引起了他極大的興趣,那就是無字天書。

但是,他的行程安排得很滿,他已經買好了去邯鄲的長途馬車票,不巧的是出發時間是在拍賣會快要結束的時候。於是,他決定事先做好準備,將自己的金幣數好並用一個個的小錢袋裝好,以便在他現有金幣的支付能力下,任何數目的金幣他都能用這些封閉好的小錢的組合來付賬。

鬼谷子也是一個非常節儉的人,他想方設法使自己在滿足上述要求的前提下,所用的錢袋數最少,並且不有兩個錢袋裝有相同的大於1的金幣數。假設他有m個金幣,你能猜到他會用多少個錢袋,並且每個錢袋裝多少個金幣嗎?

輸入輸出格式
輸入格式:
包含一個整數,表示鬼谷子現有的總的金幣數目m。其中,1≤m ≤1000000000。

輸出格式:
兩行,第一行一個整數h,表示所用錢袋個數

第二行表示每個錢袋所裝的金幣個數,由小到大輸出,空格隔開

輸入輸出樣例
輸入樣例#1: 複製
3
輸出樣例#1: 複製
2
1 2

題解:
此題遇到了分治思想,就是把一個大的問題,逐漸轉化為很多小的問題,再去求解。
比如這道題,當我們要求一個數假如為20時,我們要用盡可能少的錢袋來保證我們能
拿出1~20裡面的所有數,我們可以轉化為我們先拿10然後保證能拿1~10裡面的數。因
為1~10+10就可以表示1-20裡面的所有數。同理,下一次就是10+5+1~5,再下一次就是
10+5+3+1~2,最後就是10+5+3+1+1。這樣我們就實現了整個過程。總的來說就是將大
的問題逐漸分解拆分,最後實現我們要的目的。

程式碼:

#include <bits/stdc++.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<stack>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath> #include<map> #define exp 1e-9 #define PI acos(-1.0) #define INF 0x3f3f3f3f using namespace std; typedef long long LL; int a[100005]; //存拆分的數字 int main() { int m,sum=0; cin>>m; while(m>0) { if(m%2==0) a[sum]=m/2; else a[sum]=m/2+1; m/=2;sum++; //一步一步拆分,分治 } sort(a,a+sum); //排序 cout<<sum<<endl; for(int i=0;i<sum;i++) cout<<a[i]<<" "; return 0; }