acwing 532.货币系统

https://www.acwing.com/problem/content/534/

 

 

 题意:求一个更短的序列$b$,使得他能表示序列$a$所能表示的所有的数,并且不能表示$a$不能表示的所有的数。

分析该题,有以下性质:

①$a_1, a_2, a_3, \cdot \cdot \cdot, a_i$一定都可以被$b_i$所表示出来。

因为$b_i$必须能表示$a_i$的所有数,才能表示出$a_i$所能表示的所有的数。

②最优解的$b_1, b_2, b_3, \cdot \cdot \cdot, b_i$一定不能被其他的$b_i$所表示。

因为能被其他的$b_i$所表示,说明当前这个数是多余的,可以去掉,减短序列长度。

③最优解序列$b$的元素一定是从序列$a$的元素中选出的。

假设最优解的序列$b$的元素不是序列$a$中的元素,因为两个集合中所表示的数是一样的,所有$b$序列中的一个数字$b_i$可以由$a$中的元素所表示。

而$a$中的元素也可以由$b$中的元素表示,所以$b_i$可以由$b$中的元素所表示。

与性质②矛盾,所以最优解的序列$b$中的元素一定是从序列$a$中选出的。

思路:将数字从小到大排列,跑一遍完全背包,体积最大的边界就是数组中最大的元素。

如果当前数的方案为$0$说明当前数无法由前面的数表示,答案数加$1$。

代码:

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 
 5 using namespace std;
 6 
 7 const int N = 110, M = 25010;
 8 int f[M];
 9 int a[N];
10 int n, m;
11 
12 int main(){
13     int T;
14     cin >> T;
15     while(T --)
16     {
17         cin >> n;
18         for(int i = 1 ; i <= n ; i ++)cin >> a[i];
19         sort(a + 1, a + n + 1);
20         
21         
22         m = a[n];
23         memset(f, 0, sizeof f);
24         f[0] = 1;
25         int res = 0;
26         for(int i = 1 ; i <= n ; i ++)
27         {
28             if(!f[a[i]])res ++;
29             for(int j = a[i] ; j <= m ; j ++)
30                 f[j] += f[j - a[i]];
31         }    
32         cout << res << endl;
33     }
34     
35     return 0;
36 }

 

posted @ 2020-04-08 17:18  dzcixy  阅读(161)  评论(0)    收藏  举报