AcWing 532. 货币系统
考察:完全背包dp+线性代数
思路:
这道题其实是求给定a数组的极大无关向量组.
这里要能分析出一些性质:
- 如果(a,n)能被(b,m)所替代,那么a数组能被b数组表示
- b数组中gcd>1的一对数,大的没必要存在
- b数组是a数组的一部分元素.
假设b数组能表示a数组,且存在一个数x属于b数组而不属于a数组.根据b数组能表示a数组,那么x能被a数组的部分元素表示.又因为这些部分元素可以被b数组的某些元素表示,所以x没有存在的必要.
接下来就判断a数组哪些元素多余,根据常识,大数可以被小数表示,所以先排序,如果后面的元素可以被前面的元素表示,那么它可以被剔除
参考了Y总的代码,我自己写的是压线过的= =
为什么能这么写呢?因为上一轮标记的f[i][j]只会受到自己上一轮和这一轮相差a[i]的影响,而上一轮恒为1,所以不会改变
实际这题是求极大无关组元素个数的方法
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int N = 110,M = 25010; 7 int a[N]; 8 bool f[M]; 9 int main() 10 { 11 int T; 12 scanf("%d",&T); 13 while(T--) 14 { 15 int n,maxn = 0,ans = 0; 16 scanf("%d",&n); 17 memset(f,0,sizeof f); 18 f[0] = 1; 19 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 20 sort(a+1,a+1+n); 21 for(int i=1;i<=n;i++) 22 { 23 if(!f[a[i]]) ans++; 24 for(int j=a[i];j<=a[n];j++) 25 f[j] = f[j]|f[j-a[i]]; 26 } 27 printf("%d\n",ans); 28 } 29 return 0; 30 }