题目链接: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[j−a[i]]
即当前如果能被j−a[i]j-a[i]j−a[i]或自己在之前已经被其他的数字表示,都算为可有可无的数,这样再每次判断a[j]a[j]a[j]是否被表示来觉得是否删掉它就行了
下面是代码,附注释。
代码:
#include
#include
#include
#include
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;
}