• [完全背包] NOIP2018 货币系统


    [完全背包] NOIP2018 货币系统


    题面

    题目描述

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

    在一个完善的货币系统中,每一个非负整数的金额(x)都应该可以被表示出,即对每一个非负整数(x),都存在(n)个非负整数(t[i])满足(a[i] imes 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)

    输入输出格式

    输入格式:

    输入文件的第一行包含一个整数(T)表示数据的组数。

    接下来按照如下格式分别给出(T)组数据。 每组数据的第一行包含一个正整数(n)。接下来一行包含(n)个由空格隔开的正整数 (a[i])

    输出格式:

    输出文件共有(t)行,对于每组数据,输出一行一个正整数,表示所有与((n,a))等价的货币系统((m,b))中,最小的(m)

    Sample Input

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

    Sample Output

    2
    5


    题解

    我们先证明一个结论:

    那么要使(m)最小,((m,b))中的每一个元素必定存在于((n,a))

    下面给出这个结论的证明:

    假设((m,b))中包含一个不存在于((n,a))中的元素
    则有两种情况:

    1. 这个元素可以被((n,a))中的元素表示,那么此时(m)不满足最小,因为这个元素可以被剔除
    2. 这个元素不能被((n,a))中的元素表示,那么此时不满足((n,a))((m,b))等效

    所以((m,b))中不包含任何不存在于((n,a))中的元素

    那么我们就可以直接从((n,a))中剔除可以被自己表示的元素就可以得到((m,b))

    只需要背包一下就行了,思路还是很清晰的

    上代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int MAXN=30001;
    
    int n,ans,t,maxn=0,a[MAXN],vis[MAXN];
    bool tf[MAXN],dp[MAXN];//tf[i]表示数字i是否出现在(n,a)中
                           //dp[i]表示数字i是否可以被(n,a)表示
    
    int main(){
        scanf("%d",&t);
        while(t--){
            scanf("%d",&n);ans=n;
            memset(vis,0,sizeof(vis));
            memset(tf,0,sizeof(tf));
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++){scanf("%d",&a[i]);tf[a[i]]=true;maxn=max(maxn,a[i]);}
            sort(a+1,a+1+n);
            dp[0]=true;
            for(int i=a[1];i<=maxn;i++){
                for(int j=1;j<=vis[0];j++)if(dp[i-vis[j]])dp[i]=true;//背包
                if(dp[i]){
                        if(tf[i])ans--;//如果可以被表示,则剔除
                }else{
                    if(tf[i]){vis[++vis[0]]=i;dp[i]=1;}//否则用它来表示其他的数值
                }
            }
            printf("%d
    ",ans);
        }
    }
    
    
  • 相关阅读:
    当梦想渐行渐远的时候
    android开发系列之aidl
    看到这页代码,我要疯了
    android开发系列之性能优化
    近期的一个项目反思与总结
    IOS中摇一摇实现截屏(可实现问题反馈的功能)
    IOS设计模式浅析之外观模式(Facade)
    IOS项目开发中的文件和文件夹操作
    XCode 4.6下XIB文件提示“...could not be opened..."的问题
    "Xcode"意外退出
  • 原文地址:https://www.cnblogs.com/2016gdgzoi316/p/9994435.html
Copyright © 2020-2023  润新知