[NOIp2018] luogu P5020 货币系统
还在补暑假作业。
题目描述
你有一个由 种面值的货币组成的货币系统。定义两个货币系统等价,当且仅当 要么同时能被两个货币系统表示,要么同时不能被表示。尝试从 种面值中删除尽量多种,使得删除后得到的新系统与原系统等价。求新系统的面值种数。
Solution
一种很显然的想法是,比如 ,因为 ,所以每次我想用 的时候我都可以用 代替,所以 是废的。换句话说,如果一个数可以表示成其他若干个数的和,那么这个数应该被删除。
考虑用深度优先搜索实现这一步骤,可以得到 80 分。时间复杂度 。
#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);
}
}
设 表示 这个面值是否可以被表示出来。显然,瓶颈就是求解 数组。
考虑使用动态规划优化此过程。先将 数组排序,然后 有
这样就可通过此题。设 ,则时间复杂度为 。
#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);
}
}

浙公网安备 33010602011771号