NOIp2018 TG day1 T2暨洛谷P5020 货币系统:题解

mac2022-06-30  63

题目链接: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; }

转载于:https://www.cnblogs.com/vercont/p/10210044.html

最新回复(0)