【NOIP2018提高組】D1T2 貨幣系統
文章目錄
題目
題目描述
在網友的國度中共有
種不同面額的貨幣,第
種貨幣的面額為
,你可以假設每一種貨幣都有無窮多張。為了方便,我們把貨幣種數為
、面額陣列為
的貨幣系統記作
。
在一個完善的貨幣系統中,每一個非負整數的金額 都應該可以被表示出,即對每一個非負整數 ,都存在 個非負整數 滿足 的和為 。然而,在網友的國度中,貨幣系統可能是不完善的,即可能存在金額 不能被該貨幣系統表示出。例如在貨幣系統 , 中,金額 就無法被表示出來。
兩個貨幣系統 和 是等價的,當且僅當對於任意非負整數 ,它要麼均可以被兩個貨幣系統表出,要麼不能被其中任何一個表出。
現在網友們打算簡化一下貨幣系統。他們希望找到一個貨幣系統 ,滿足 與原來的貨幣系統 等價,且 儘可能的小。他們希望你來協助完成這個艱鉅的任務:找到最小的 。
輸入輸出格式
輸入格式
輸入檔案的第一行包含一個整數
,表示資料的組數。
接下來按照如下格式分別給出 組資料。 每組資料的第一行包含一個正整數 。接下來一行包含 個由空格隔開的正整數 。
輸出格式
輸出檔案共有
行,對於每組資料,輸出一行一個正整數,表示所有與
等價的貨幣系統
中,最小的
。
輸入輸出樣例
輸入樣例:
2
4
3 19 10 6
5
11 29 13 19 17
輸出樣例:
2
5
說明
在第一組資料中,貨幣系統
和給出的貨幣系統
等價,並可以驗證不存在
的等價的貨幣系統,因此答案為
。 在第二組資料中,可以驗證不存在
的等價的貨幣系統,因此答案為
。
資料規模與約定
對於
的資料,滿足
,
。
思路
先排個序。
如果當前面值能由前面的面值湊出,當前面值就可以不要了。
完全揹包即可。
本來以為多年準備一場空,不開滾動見祖宗
,結果在洛谷上還過了。
其實考場上都不知道是完全揹包,只知道是DP。
考場程式碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
#define MAXN 100
#define MAXA 25000
int N,A[MAXN+5];
bool dp[MAXN+5][MAXA+5];
int main(){
freopen("money.in" ,"r", stdin);
freopen("money.out","w",stdout);
int T=read();
while(T--){
N=read();
for(int i=1;i<=N;i++)
A[i]=read();
sort(A+1,A+N+1);
memset(dp,0,sizeof dp);
dp[0][0]=1;
int Ans=N;
for(int i=1;i<=N;i++){
for(int j=0;j<=A[N];j++){
dp[i][j]=dp[i-1][j];
if(j>=A[i])
dp[i][j]|=dp[i][j-A[i]]|dp[i-1][j-A[i]];
}
Ans-=dp[i-1][A[i]];
}
printf("%d\n",Ans);
}
}