[NOIp2018] luogu P5020 货币系统

还在补暑假作业。

题目描述

你有一个由 N N N 种面值的货币组成的货币系统。定义两个货币系统等价,当且仅当 ∀ x ∈ N ∗ \forall x\in\N^* xN 要么同时能被两个货币系统表示,要么同时不能被表示。尝试从 N N N 种面值中删除尽量多种,使得删除后得到的新系统与原系统等价。求新系统的面值种数。

Solution

一种很显然的想法是,比如 { 2 , 3 , 5 } \{2,3,5\} {2,3,5},因为 2 + 3 = 5 2+3=5 2+3=5,所以每次我想用 5 5 5 的时候我都可以用 2 + 3 2+3 2+3 代替,所以 5 5 5 是废的。换句话说,如果一个数可以表示成其他若干个数的和,那么这个数应该被删除。

考虑用深度优先搜索实现这一步骤,可以得到 80 分。时间复杂度 O ( T n n ) O(Tn^n) O(Tnn)

#include<cstdio>
#include<cstdlib>
#include<cstring>

const int MAXN=110;
const int MAxm=25010;

int T,n;
int a[MAXN+10];

int dfs(int x,int y){
	if(x<0) return 0;
	if(!x) return 1;
	int c=0;
	for(int i=1;i<=n;++i){
		if(!c&&y!=i) c=dfs(x-a[i],y);
		if(c) break;
	}
	return c;
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;++i)
			scanf("%d",&a[i]);
		int ans=n;
		for(int i=1;i<=n;++i)
			ans-=dfs(a[i],i);
		printf("%d\n",ans);
	}
}

f [ i ] f[i] f[i] 表示 i i i 这个面值是否可以被表示出来。显然,瓶颈就是求解 f f f 数组。

考虑使用动态规划优化此过程。先将 a a a 数组排序,然后 ∀ a [ i ] \forall a[i] a[i] f [ j ] = f [ j ]  or  f [ i − a [ j ] ] f[j]=f[j]\text{ or }f[i-a[j]] f[j]=f[j] or f[ia[j]]
这样就可通过此题。设 max ⁡ a = M = 25   000 \max a=M=25\ 000 maxa=M=25 000,则时间复杂度为 O ( T M 2 ) O(TM^2) O(TM2)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

const int MAXN=110;
const int MAXM=25010;

int T,n;
int a[MAXN+10];
int f[MAXM+10];

int dfs(int x,int y){
	if(x<0) return 0;
	if(!x) return 1;
	int c=0;
	for(int i=1;i<=n;++i){
		if(!c&&y!=i) c=dfs(x-a[i],y);
		if(c) break;
	}
	return c;
}
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		for(int i=1;i<=n;++i)
			scanf("%d",&a[i]);
		std::sort(a+1,a+n+1);
		memset(f,0,sizeof(f));f[0]=1;
		int ans=n;
		for(int i=1;i<=n;++i){
			if(f[a[i]]){
				--ans;
				continue;
			}
			for(int j=a[i];j<=a[n];++j)
				f[j]=f[j]||f[j-a[i]];
		}
		printf("%d\n",ans);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值