b数组满足3个性质:
1.a数组的任何一个数一定可以被b数组若干个数表示出来(从a、b数组等价的定义,显然可以得出);
2.b数组中的任何一个数不能被b数组中若干个数表示出来(如果存在,即使踢去仍不影响结果,是个冗余值,不符合最优解);
3.在最优解中,b数组中的数一定都是从a数组中选择的。
证明:
①若b[i]不属于a数组,且b[i]不能被a数组中的若干个数表示出来
那么b数组能表示出a数组不能表示出的数,与条件矛盾,所以不成立
②若b[i]不属于a数组,且b[i]能被a数组中的若干个数表示出来
因为a数组中的任何一个数都可以用b数组中的若干个数表示出来,说明b[i]可以被b数组中若干个数表示出来,与性质2矛盾。
综上:性质3成立
根据性质3,b数组的取值范围就被限制在了a数组中,并且可以知道这道题的解决方法就是检查a数组中的每一个数是否可以用其它的数表示出来,如果可以说明这个数不必要,如果不可以则是必要的。
因为数组中的数都是正整数,因此任何一个数都是被小于自身的数表示的,于是可以先将a数组排序,要想检查a[i]是否可以被a数组中
的若干个数表示出来,只要针对a[1~i-1]中的数即可,问题就转化成完全背包问题。
C++ 代码
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 25010;
int n;
int a[N];
int f[N];
int main()
{
int T;
cin >> T;
while (T -- )
{
cin >> n;
for(int i = 0 ; i < n ; i++) cin >> a[i];
sort(a , a + n);
int res = 0;
memset(f , 0 , sizeof f);
f[0] = 1;
for(int i = 0 ; i < n ; i++)
{
if(!f[a[i]]) res++;//如果a[i]不能被表示,则b数组一定添加a[i]
for(int j = a[i] ; j <= a[n - 1] ; j++)
f[j] += f[j - a[i]];
}
cout << res << endl;
}
return 0;
}
性质3分类讨论可是太好了😄