嘘~ 正在从服务器偷取页面 . . .

洛谷P5020 [NOIP2018 提高组] 货币系统 题解


洛谷P5020 [NOIP2018 提高组] 货币系统 题解

题目链接:P5020 [NOIP2018 提高组] 货币系统

题意:在网友的国度中共有 \(n\) 种不同面额的货币,第 \(i\) 种货币的面额为 \(a[i]\),你可以假设每一种货币都有无穷多张。为了方便,我们把货币种数为 \(n\) 、面额数组为 \(a[1..n]\) 的货币系统记作 \((n,a)\)

在一个完善的货币系统中,每一个非负整数的金额 \(x\) 都应该可以被表示出,即对每一个非负整数 \(x\) ,都存在 \(n\) 个非负整数 \(t[i]\) 满足 \(a[i] \times t[i]\) 的和为 \(x\) 。然而, 在网友的国度中,货币系统可能是不完善的,即可能存在金额 \(x\) 不能被该货币系统表示出。例如在货币系统 \(n=3 ,a=[2,5,9]\) 中,金额 \(1,3\) 就无法被表示出来。

两个货币系统 \((n,a)\)\((m,b)\) 是等价的,当且仅当对于任意非负整数 \(x\) ,它要么均可以被两个货币系统表出,要么不能被其中任何一个表出。

现在网友们打算简化一下货币系统。他们希望找到一个货币系统 \((m,b)\) ,满足 \((m,b)\) 与原来的货币系统 \((n,a)\) 等价,且 \(m\) 尽可能的小。他们希望你来协助完成这个艰巨的任务:找到最小的 \(m\)

输入输出样例

输入 #1

2 
4 
3 19 10 6 
5 
11 29 13 19 17 

输出 #1

2   
5  

观察第一组数据,可以发现其等价于 3 10

因为 \(19\)\(6\) 均可以用 \(3\)\(10\) 替代

而第二组,每一种都是有价值的,不可替代

考虑 \(dp\)

\(dp[i]\) 表示凑出 \(i\) 最多需要花费的金额种类

显然这个是个完全背包。

\(dp[a[i]]=1\) 则说明 \(a[i]\) 是有价值的面额

然后就没了,代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
#define N (int)(3e4+15)
int Q,n,mx;
int a[115],dp[N];
signed main()
{
    read(Q);
    while(Q--)
    {
        memset(dp,0xc0,sizeof(dp));
        read(n);dp[0]=0;mx=-INF;
        for(int i=1; i<=n; i++)
        {
            read(a[i]);
            mx=max(mx,a[i]);
        }
        for(int i=1; i<=n; i++)
            for(int j=a[i]; j<=mx; j++)
                dp[j]=max(dp[j],dp[j-a[i]]+1);
        int res=0;
        for(int i=1; i<=n; i++)
            if(dp[a[i]]==1)++res;
        write(res);pc('\n');
    }
    return 0;
}

其实这个 \(b\) 是可以证明有 $b a $ 的

但是,OI不需要严谨证明。OI靠得是OI直觉。


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录