NOIP2018D1T2 货币系统

题面
这道题我是亲自在考场上考过的
先说题解吧
一个货币系统中 x x x是没用的,当且仅当他能被系统中别的货币表示
我们拿 R M B RMB RMB来举个例子
发现所有的钱都能被一分钱表示出来 所以只留一个一分钱的就好了!

咳咳 不闹了

题面可以简述为:给你一个货币系统 A A A 让我们可以给他简化 使得所有可以表示的钱还能表示出来。输出最后简化剩下的货币数量。
我们考虑一个像背包的东西,由于我菜逼的背包技术,我也不知道这是啥背包…反正我能做出来我乐意
每次操作到 a i a_i ai时,考虑能不能被它前面的数字所组成
我们知道如果 x x x能被前 i i i个数组成且组成 x x x的数当中包含 a i a_i ai那么 ( x − a i ) (x-a_i) (xai)也必然能被前 i i i个数来组成
那么我们很容易想到定义 f ( x ) f(x) f(x)表示 x x x能否被组成,那么根据上面的想法显然有 f ( x ) = f ( x ) ∨ f ( x − a i ) f(x) = f(x) \vee f(x-a_i) f(x)=f(x)f(xai)
直接上代码

#include
using namespace std;
inline void read(int &x){
	int s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+(ch&15);ch=getchar();}
	x=s*w;
}
int t,n,ans,a[101];
bool vis[30000];
int main(){
	read(t);
	while(t--){
		read(n);ans=n;
		for(int i=1;i<=n;i++)read(a[i]);
		memset(vis,0,sizeof(vis));
		sort(a+1,a+1+n);vis[0]=1;
		for(int i=1;i<=n;i++){
			if(vis[a[i]])ans--;
			for(int j=a[i];j<=a[n];j++)vis[j]=vis[j]|vis[j-a[i]];
		}
		printf("%d\n",ans);
	}
}

这几天要好好复习背包九讲了,别再像去年那样连这种水分都不要…

你可能感兴趣的:(dp,NOIP原题)