#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<double,double> PDD;
typedef vector<int> VI;
const int mod = 1000000007;
int n,m,t;
int v[1010];
int w[1010];
int a[1010];
int h[250001];
int dp[250001];//能表示的金额
int main(){
cin>>t;
while(t--){
memset(dp,0,sizeof dp);
memset(a,0,sizeof a);
cin>>n;
dp[0] = 1;
for(int i=1;i<=n;i++){
cin>>a[i];
m = max(m,a[i]);
}
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
dp[j] += dp[j-a[i]];
}
}
int ct = 0 ;
for(int i=1;i<=n;i++){
if(dp[a[i]] == 1){
ct++;
}
}
cout<<ct<<endl;
}
}
完全背包问题
转移方程 dp[ i ][ j ] = dp[ i-1 ][ j ] + dp[ i-1 ][ j-a[i] ];
滚动数组优化下 dp[ j ] += dp[ j-a[i] ];
观察方案数是很重要的,考虑到货币体系内,一个面值如果能被面值组合表示,那么这种货值就是不需要的,而一种货币如果是必须的,那么他就一定只能被自己表示,即表示他的方案是1。
统计方案数和价值有一点区别,大概大于求价值是只追求最大值,转移方程可以有重叠部分(当然这题并没有)
而方案数是要将所有情况统计在一起,因此求方案数的转移方程要求没有重复也没遗漏