题目链接: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<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;
}
转载于:https://www.cnblogs.com/vercont/p/10210044.html