题目传送门
解题思路:
首先证明一个事实,最终求出的货币系统中的元素,一定出现在原来的货币系统中,也就是不存在原来货币系统之外的元素。
那么显然的是,最终我们求得到的集合就是(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 ",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