【NOIP2018Day1T2】【洛谷P5020】貨幣系統

問題描述

在網友的國度中共有 n 種不一樣面額的貨幣,第 i 種貨幣的面額爲 a[i],你能夠假設每一種貨幣都有無窮多張。爲了方便,咱們把貨幣種數爲 n、面額數組爲 a[1..n] 的貨幣系統記做 (n,a)。html

在一個完善的貨幣系統中,每個非負整數的金額 x 都應該能夠被表示出,即對每個非負整數 x,都存在 n 個非負整數 t[i] 知足 a[i]×t[i] 的和爲 x。然而, 在網友的國度中,貨幣系統多是不完善的,便可能存在金額 x 不能被該貨幣系統表示出。例如在貨幣系統 n=3, a=[2,5,9] 中,金額 1,3 就沒法被表示出來。數組

兩個貨幣系統 (n,a) 和 (m,b) 是等價的,當且僅當對於任意非負整數 x,它要麼都可以被兩個貨幣系統表示出,要麼不能被其中任何一個表示出。spa

如今網友們打算簡化一下貨幣系統。他們但願找到一個貨幣系統 (m,b),知足 (m,b) 與原來的貨幣系統 (n,a)等價,且 m 儘量的小。他們但願你來協助完成這個艱鉅的任務:找到最小的 m。code

輸入格式

輸入文件的第一行包含一個整數 T,表示數據的組數。htm

接下來按照以下格式分別給出 T 組數據。 每組數據的第一行包含一個正整數 n。接下來一行包含 n 個由空格隔開的正整數 a[i]。blog

輸出格式

輸入文件的第一行包含一個整數 T,表示數據的組數。string

接下來按照以下格式分別給出 T 組數據。 每組數據的第一行包含一個正整數 n。接下來一行包含 n 個由空格隔開的正整數 a[i]。it

樣例輸入

2
4
3 19 10 6
5
11 29 13 19 17io

樣例輸出

2
5class

提示

在第一組數據中,貨幣系統 (2,[3,10]) 和給出的貨幣系統 (n,a) 等價,並能夠驗證不存在 m<2 的等價的貨幣系統,所以答案爲 2。 在第二組數據中,能夠驗證不存在 m<n 的等價的貨幣系統,所以答案爲 5。

數據範圍

題解

研究一下樣例,發現新貨幣系統是舊貨幣系統的子集。因而大膽猜測:新貨幣系統必定是舊貨幣系統刪掉幾種面額的貨幣,而且被刪掉的面額能夠被沒被刪掉的面額表示出來。

(遵循大膽猜測不用證實原則的大佬自動跳過這段)


 證實:反證法

    反正就是這樣

    證實完畢

  若是以上結論不成立,無非存在如下兩種狀況:

    一、新貨幣系統中存在舊貨幣系統所沒有的面額,記爲a[i],a[i]不能被舊貨幣系統表示出來

    二、新貨幣系統中存在舊貨幣系統所沒有的面額,記爲a[j], a[j]可以被舊貨幣系統表示出來

  對於第一種狀況,顯然新貨幣系統能夠表示出舊貨幣系統所表示不出的面額,由於a[i]自己就是一種舊貨幣系統所表示不出的面額,因而這種狀況不成立。

  對於第二種狀況,顯然a[j]是多餘的,由於a[j]可以被表示出來,因此須要用到a[j]時能夠用表示出a[j]的這些面額代替,因此a[j]能夠刪掉,因而這種狀況也不成立。

  因此,上述結論:新貨幣系統必定是舊貨幣系統刪掉幾種面額的貨幣,而且被刪掉的面額能夠被沒被刪掉的面額表示出來成立。


那麼咱們只須要求給訂貨幣系統最多能夠刪掉多少種面額。

設f[i]表示面額爲i可否被表示出來,則

f[i]=f[i]|f[j](1<=j<k,a[k]<i)

在動規循環時順便計算f[i]==false && i∈a的個數,用總數減去f[i]==false && i∈a的個數,就是答案

時間複雜度 5*107

 

 

 1 #include <algorithm>
 2 #include <cstring>
 3 #include <cstdio>
 4 int T,n,m,a[105];
 5 bool f[25005];
 6 int main()
 7 {
 8     
 9     int i,j,k;
10     scanf("%d",&T);
11     while (T--)
12     {
13         scanf("%d",&n);
14         for (i=1;i<=n;i++) scanf("%d",&a[i]);
15         m=n;
16         std::sort(a+1,a+n+1);
17         memset(f,0,sizeof(f));
18         f[a[1]]=1;  k=1;
19         for (i=a[1]+1;i<=a[n];i++)
20         {
21             for (j=1;j<=k && !f[i];j++)
22               f[i]=f[i]|f[i-a[j]];  
23             if (i==a[k+1])
24             {
25                 k++;
26                 if (f[i]) m--;
27                 else f[i]=1;
28             }
29         }
30         printf("%d\n",m);
31     }
32     return 0;
33 }
相關文章
相關標籤/搜索