题意:
给出一组数据,让你简化这个数组,使得原数组中任意一个元素都可以被简化后的数组表示,表示的方式为从简化后的数组抽取数组中任意元素任意次累加和等于该元素,求简化后数组的最小长度。

解题思路:
这道题类似于牛客的另一道题砝码,不过砝码可以相减,但是思路都差不多。首先如果一个元素能被已经选择的元素表示出来,那么这个元素就不用再取了,所以我们可以建立一个标记数组用来标记某个数是否可以被已经选择的数进行表示(类似于dp优化),因此我们可以对数组从小到大进行排序,每取一个数,就更新一下标记数组,标记的条件是若某个数被标记了,那么这个数加上本轮选取的数也会被标记。初始条件vis[0]=1。

代码如下:

#include<bits/stdc++.h>
#define LL long long
#define all(x) (x).begin(),(x).end()
#define le(x) ((int)(x).size())
#define pii pair<int,int>
#define PII pair<LL,LL>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define db printf("Here!\n");
using namespace std;
const double eps=1e-8;
const double Pi=4.0*atan(1.0);
const LL inf=1e10+10;
const int N=3e5+5;
const int M=2e6+5;
const int mod=1e9+7;
int n,m,k,t,T,len,op,x,y,z,ok;
int a[N],vis[N];
void solve(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    sort(a+1,a+1+n);
    int ans=0;
    for(int i=1;i<=a[n];i++)vis[i]=0;
    vis[0]=1;
    for(int i=1;i<=n;i++){
        if(vis[a[i]])continue;//如果这个数可以被已经选择的数进行表示,那么就不需要再进行选择了
        ++ans;//否则答案加1
        for(int j=0;j<=a[n];j++){
            if(vis[j])vis[j+a[i]]=1;//如果j可以被表示,那么j+本轮选择的数a[i]也可以被表示
        }
    }
    printf("%d\n",ans);
}
int main(){
    int o;scanf("%d",&o);
    while(o--){
        solve();
    }
    return 0;
}