[USACO13NOV]没有找零No Change

来源:互联网 发布:青山知可子女机械人511 编辑:程序博客网 时间:2024/05/22 23:26

[USACO13NOV]没有找零No Change

状压Dp

题解:

f[S]表示用了集合S里的coin之后做多购买前多少个。
转移的时候枚举一个coin,二分一下。
统计答案的时候,所有f[S]==n的算出钱数来,取个min。

Code:

#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#define D(x) cout<<#x<<" = "<<x<<"  "#define E cout<<endlusing namespace std;typedef long long ll;int n,m; ll ans,tot;ll coin[21],sum[100005];int f[100005];int main(){    freopen("a.in","r",stdin);    scanf("%d%d",&m,&n);    for(int i=0;i<m;i++){        scanf("%lld",coin+i);        tot+=coin[i];    }    for(int i=1;i<=n;i++){        scanf("%lld",sum+i);        sum[i]+=sum[i-1];    }    int All=(1<<m)-1;    for(int S=0;S<=All;S++){        for(int i=0;i<m;i++){            if((S>>i)&1){                int x=f[S^(1<<i)];                x=upper_bound(sum+x,sum+n+1,coin[i]+sum[x])-sum-1;                f[S]=max(f[S],x);            }        }    }    ans=1e17;    for(int S=0;S<=All;S++){//      D(S); D(f[S]); E;        if(f[S]==n){            ll res=0;            for(int i=0;i<m;i++){                if((S>>i)&1) res+=coin[i];            }            ans=min(ans,res);        }    }    if(ans>tot) puts("-1");    else printf("%lld\n",tot-ans);}
原创粉丝点击