题解:NOIP2018货币系统

在网友的国度中共有 nn 种不同面额的货币,第 ii 种货币的面额为 a[i]a[i],你可以假设每一种货币都有无穷多张。为了方便,我们把货币种数为 nn、面额数组为 a[1…n]a[1…n] 的货币系统记作 (n,a)(n,a)。
在一个完善的货币系统中,每一个非负整数的金额 xx 都应该可以被表示出,即对每一个非负整数 xx,都存在 nn 个非负整数 t[i]t[i] 满足 a[i] \times t[i]a[i]×t[i] 的和为 xx。然而, 在网友的国度中,货币系统可能是不完善的,即可能存在金额 xx 不能被该货币系统表示出。例如在货币系统 n=3n=3, a=[2,5,9]a=[2,5,9] 中,金额 1,31,3 就无法被表示出来。
两个货币系统 (n,a)(n,a) 和 (m,b)(m,b) 是等价的,当且仅当对于任意非负整数 xx,它要么均可以被两个货币系统表出,要么不能被其中任何一个表出。
现在网友们打算简化一下货币系统。他们希望找到一个货币系统 (m,b)(m,b),满足 (m,b)(m,b) 与原来的货币系统 (n,a)(n,a) 等价,且 mm 尽可能的小。他们希望你来协助完成这个艰巨的任务:找到最小的 mm。

对于一个NOIP炸了的人,看着这个题目真的是一把辛酸泪…

fsz 大佬的模拟 — 70 ‘
llc 大佬的搜索 — 90 ’
wfy 大佬手抖的小凯剪枝 — 100 ’

然后…
我的脑抽 — (不想说话

这个题目就是个简单的DP(记忆化搜索也可以),最后算下来就是个普通的完全背包

f [ i ] 表示 i 面值最多能被几张钱表示 则若其不能被表示 f [ i ] = - i n f 能表示且只有它自己则 f [ i ] =1
初始化 f [ 0 ] = 0
然后就是裸的背包
状态转移方程为
f [ i ] = m a x ( f [ i ] , f [ i - a [ j ] ] + 1 )

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int a[500],n,cnt,q[50000];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(q,-63,sizeof q);
        int ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        q[0]=0;
        for(int i=1;i<=n;i++)
            for(int j=a[i];j<=30000;j++)
                q[j]=max(q[j],q[j-a[i]]+1);
        for(int i=1;i<=n;i++)
            if(q[a[i]]==1) ans++;
        printf("%d\n",ans);
    } 
    return 0;
}

是我太弱了啊

猜你喜欢

转载自blog.csdn.net/weixin_43464026/article/details/88537202