2018D1T2 货币系统

2018D1T2 货币系统

problem

记货币种类为\(n\),面额数组为\(a[1...n]\)的货币系统为\((n,a)\)。货币系统\((n,a)\)\((m,b)\)等价,当且仅当对于\(\forall x\in \mathbf N\)\(x\)要么均可以被两个货币系统表示,或者不能被任何一个表示。
给定一个货币系统\((n,a)\),求与其等价的货币系统\((m,b)\),并使\(m\)尽可能小。

solution

我们把货币系统\((n,a)\)看做集合\(A\),货币系统\((m,b)\)看做集合\(B\),我们猜测\(B⊆ A\),接下来进行证明。

一些奇奇怪怪的证明

证明1\(A\)集合内不能被其他数表示的数必然存在于\(B\)集合内。
证明:我们设\(x\in A\)\(x\)不能被\(A\)集合中除他以外的元素表示出来。(即\(\forall Y⊆A,\exists x\in A,x\notin T,x\neq \sum\limits_{a\in T} a\)
我们假设\(x\notin B\),由于两个集合等价,所以\(B\)集合一定能够表示出\(x\),换句话说\(\exists X⊆B,x=\sum\limits_{b\in X}b\)

那么\(X\)集合中的元素中至少有一个不在\(A\)内,并且不能被集合\(A\)里的元素组成(因为如果不存在的话\(A\)内的元素就可以表示\(x\)了)。这样与\(B\)集合的定义产生矛盾。这样我们可以证明。
证明2\(B⊆A\)
证明:假设\(\exists x\in B,x\notin A\)
根据题目条件,\(x\)一定可以被\(A\)集合内的数字所组成。那么必然\(\exists U⊆A,U={a_i}\)可以用来组成\(x\)并且这些元素都不能被\(A\)集合内的元素组成(因为如果\(a_i\)能被\(A\)集合内其他数组成,那么必然可以用那些数来代替\(a_i\)),根据上一个结论我们知道\(U⊆B\).
那么也就是说\(x\)可以被\(B\)集合内的数字组成,那么凡是可以用\(x\)组成的数都可以被\(B\)集合内的其他数字组成,那么也就是说即便从集合\(B\)中去掉\(x\)元素也依旧满足条件,这就与\(B\)集合的定义矛盾。
所以\(\forall x\in B,x\in A \iff B⊆A\)

算法

最后:\(A\)集合中,能被其他数组成的数必然不在\(B\)集合内
到这里,我们只需要计算出\(A\)集合内存在多少个能被其他数计算出来的就行了。
使用完全背包。
根据常识,我们知道\(x\)只能被他小的数字组成。
我们对数组排个序,然后对于每一个数考虑能不能被它前面的数字所组成。我们知道如果\(x\)能够被前\(i\)个数字组成,并且组成\(x\)的数中包含\(a_i\),那么\(x-a_i\)也可以用前\(i\)个数来组成。那么我们很容易想到定义\(f(x)\)表示\(x\)能否被组成,则\(f(x)=f(x)∨f(x-a_i)\)

code

#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define MAXAI 25005
#define MAXN 105
int f[MAXAI];
int a[MAXN];
int main()
{
    int i,j,n,T,ans;
    scanf("%d",&T);
    while(T--)
    {
        memset(f,0,sizeof(f));
        scanf("%d",&n);ans=n;
        for(i=1;i<=n;i++) scanf("%d",&a[i]);
        sort(a+1,a+n+1);
        f[0]=1;
        for(i=1;i<=n;i++)
        {
            if(f[a[i]])
            {
                ans--;
                continue;
            }
            for(j=a[i];j<=a[n];j++)
            {
                f[j]=f[j]|f[j-a[i]];
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2020-10-12 13:13  刘子闻  阅读(105)  评论(0编辑  收藏  举报