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);
}