洛谷 P5020 货币系统

题目传送门

解题思路:

首先证明一个事实,最终求出的货币系统中的元素,一定出现在原来的货币系统中,也就是不存在原来货币系统之外的元素。 

那么显然的是,最终我们求得到的集合就是(n,a)中不能被其他数字表示的数的集合。并且我们发现,如果一个数能被表示,那么显然会被比它小的数表示。

所以我们可以把原来的货币按照面值升序排序,从小到大考虑每一个数,设f[i]为只用到当前考虑的数之前的数能否表述出数字i。那么对于当前数字,如果它能被前面的数表示,那么可以扔掉。否则,将它加入答案,并更新f数组(其实是一个类似背包的问题)

 AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 
 6 using namespace std;
 7 
 8 int t,n,a[101],ans;
 9 bool f[25001];
10 
11 void solve() {
12     scanf("%d",&n);
13     for(int i = 1;i <= n; i++)
14         scanf("%d",&a[i]);
15     ans = n;
16     sort(a+1,a+n+1);
17     memset(f,0,sizeof(f));
18     f[0] = 1;
19     for(int i = 1;i <= n; i++) {
20         if(f[a[i]]) ans--;
21         for(int j = a[i];j <= a[n]; j++) 
22             f[j] = f[j] | f[j-a[i]];
23     }
24     printf("%d\n",ans);
25 }
26 
27 int main() {
28     scanf("%d",&t);
29     for(int i = 1;i <= t; i++) 
30         solve();
31     return 0;
32 }

//NOIP提高 2018 Day1 T2

posted @ 2019-07-29 23:46  Mr^Simon  阅读(163)  评论(0编辑  收藏  举报