NOIP2016模擬 JackMa 貪心

NKOJ 3847 (標題被手動和諧)

問題描述

Mr_he 因討厭???(手動和諧)而徹底放棄網購,他的日常用品都要到商場去購買,而且必須付現金。但是現 金購買,經常會遇到找零的問題,那麼現在請你幫助他解決這樣一個問題: 現在 Mr_he 手上有 n 種不同面值的硬幣,每種硬幣有無限多個。爲了方便購物,他希望帶儘量 少的硬幣,但是要能組合出 1 到 m 之間的任意值。

輸入格式

第一行爲兩個整數:m 和 n,他們的意義如題目描述。
接下來的 n 行,每行一個整數,第 i+1 行的整數表示第 i 種硬幣的面值

輸出格式

最少需要攜帶的硬幣數量,如果無解則輸出-1。

樣例輸入

20 4
1
2
5
10

樣例輸出

5

數據範圍

50%的數據:1<=n<=10, 1<=m<=10^3;
100%的數據:1<=n<=100,1<=m<=10^9;

來源:重慶一中


m的範圍非常大,如果DP的話就只能看能否把m這一維壓縮,然而這是比較困難的。

首先考慮無解的情況,很顯然,如果沒有1就無解。只要有1就一定有解,因爲每種硬幣是無限多的。

注意到大面值硬幣是湊不出小面值的,但如果我們要硬幣儘量少,大面值的又不能太少。所以按面值從小到大的順序討論,儘量用已經選的硬幣湊成大面值硬幣的面值-1,如果不能恰好湊成就多用一個。詳情見代碼:

#include<stdio.h>
#include<algorithm>
#include<cmath>
using namespace std;

int M,N,A[105],Ans;

int main()
{
    int i,x,tot=0,t;
    //tot表示當前可以湊成的最大面值,且tot以下的都能湊成
    scanf("%d%d",&M,&N);
    for(i=1;i<=N;i++)scanf("%d",&A[i]);

    A[N+1]=M+1;
    sort(A+1,A+N+2);
    if(A[1]!=1)return puts("-1"),0;//沒有1則無解

    for(i=2;i<=N+1&&A[i]<=M+1;i++)//注意有可能出現M比某種硬幣的面值更小
    {
        if(A[i]-1<=tot)continue;
        t=ceil(1.0*(A[i]-1-tot)/(A[i-1]));//向上取整,因爲如果無法恰好湊成就多用一個
        Ans+=t;
        tot+=A[i-1]*t;
    }

    printf("%d",Ans);
}
發佈了105 篇原創文章 · 獲贊 23 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章