题解 P5020 【货币系统】
题目名称:货币系统
来源:2018年NOIP提高组
链接
博客链接
- 博客园
- CSDN
- 洛谷博客
- 洛谷题解
题目链接
- LibreOJ(2951)
- 大视野在线评测(1425)
题目大意
已知货币系统
两个货币系统
找到一个货币系统
提示
因为钱掉进了水里,所以这是一道水题。
题解
输入每种面额后,先将其从小到大排序。
引理
如果一个面额无法被比它小的面额凑出来,那么必须选,否则一定不选。
证明:前者很显然,因为这个数不可能被比其更大的数凑出来。
后者,因为这个数可以被其他数凑出来,那么需要这个数组成的数只需要凑成这个数的数就可以了。
于是我们按顺序做完全背包,如果发现没被前面的数背包得到就选,否则不选。
//C++
#include<bits/locale_facets.h>
#include<memory.h>
#include<stdio.h>
using namespace std;
inline void output(long long value);
inline long long input();
short a[101],able[25001];
int main()
{
short T=input();
while(T--)
{
short n=input(),maximum=0;
short must=n;
for(short i=1;i<=n;i++)maximum=max(maximum,a[i]=input());
able[0]=true;
for(short i=1;i<=n;i++)
for(short j=a[i];j<=maximum;j++)
if(able[j-a[i]])able[j]++;
for(short i=1;i<=n;i++)
if(able[a[i]]>1)must--;
memset(able,0,50002);
output(must),putchar('\n');
}
return 0;
}
inline void output(long long o)
{
if(o<0)putchar('-'),o=-o;
if(o>=10)output(o/10);
putchar(o%10^'0');
}
inline long long input()
{
bool positive=true;
char now=getchar();
long long i=0;
for(;!isdigit(now);now=getchar())
if(now=='-')positive=!positive;
for(;isdigit(now);now=getchar())i=(i<<3)+(i<<1)+(now^'0');
return positive?i:-i;
}