2018D1T2 货币系统

2018D1T2 货币系统

problem

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

solution

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

一些奇奇怪怪的证明

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

那么(X)集合中的元素中至少有一个不在(A)内,并且不能被集合(A)里的元素组成(因为如果不存在的话(A)内的元素就可以表示(x)了)。这样与(B)集合的定义产生矛盾。这样我们可以证明。
证明2(B⊆A)
证明:假设(exists xin B,x otin 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 xin B,xin 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
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/liuziwen0224/p/2018d1t2.html