题目链接:https://www.luogu.org/problemnew/show/P5020

这道题感觉比较水啊,身为普及组蒟蒻都不费力的做出来了,而且数据范围应该还能大一些,n起码几万几十万都不一定T。求过~

分析:

本题是类似完全背包问题,分析样例我们可以得出结论:一种面值的货币如果可以由此系统中的其他货币组合而来,那么它就是可有可无的。

由此我们分析:不妨只在一个系统中做出删减,删掉尽可能多的面值不就行了吗?

对于每个数,我们判断其能否组合出,就成了典型的背包问题。

我们设 f [ i ] f[i] f[i]表示i是否可以在题目给出的系统中被表示出来。那么每一次就可以转移为:

f [ j ] = f [ j ] f [ j a [ i ] ] f[j]=f[j]||f[j-a[i]] f[j]=f[j]f[ja[i]]

即当前如果能被 j a [ i ] j-a[i] ja[i]或自己在之前已经被其他的数字表示,都算为可有可无的数,这样再每次判断 a [ j ] a[j] a[j]是否被表示来觉得是否删掉它就行了
下面是代码,附注释。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int f[25005],a[105];//看这数组小的不可思议。。。
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)//这种读入多组数据的方法比较方便。
	{
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
		}
		int ans=n;
		sort(a+1,a+n+1);//从小到大排序
		memset(f,0,sizeof(f));//每次清空
		f[0]=1;
		for(int j=1;j<=n;j++)
		{
			if(f[a[j]]==1)
			{
				ans--;
				continue;
			}
			for(int k=a[j];k<=a[n];k++)
			{
				f[k]=f[k]||f[k-a[j]];
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}