Rikka with Coin(想法)

original link - http://acm.hdu.edu.cn/showproblem.php?pid=6685

题意:

有4种硬币:10,20,50,10010,20,50,10010,20,50,100,每种无限个,现在你要挑选最少的个数,使得可以组成给出的n个价格。

解析:

开始想到超过100的应该都是直接100比较少。所以模了10到90,发现只需要10,20,20,5010,20,20,5010,20,20,50这4个就可以组成任意了,所以就将所有价格模100后塞到set中,做了一个背包求最少的选择方案。

但是后来暴力对拍才发现,90和110的情况比较特殊,110可以用20,20,20,5020,20,20,5020,20,20,50组成。所以特判一下就行了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
const int maxn=209;
int a[maxn];

int main(){
    int t;scanf("%d",&t);
    while(t--){
        int n;scanf("%d",&n);
        int _100=0;
        unordered_set<int>S;
        int b=0;
        rep(i,1,n){
            scanf("%d",a+i);
            int tmp=a[i]%100;
            if(tmp%10){
                b=1;
            }
            S.insert(tmp);
        }

        if(b){
            printf("-1\n");
            continue;
        }

        int val[9]={1,1,1,1,2,2,2,2,5};
        int mi=100;
        int en=(1<<9)-1;
        rep(i,0,en){
            int dp[10];
            memset(dp,0,sizeof dp);
            dp[0]=1;
            rep(j,0,8){
                per(siz,8,0){
                    if(dp[siz]==0||siz+val[j]>9)continue;
                    if(i&(1<<j)){
                        dp[siz+val[j]]=1;
                    }
                }
            }
            int can=1;
            for(auto P:S){
                if(!dp[P/10]){can=0;break;}
            }
            if(can)mi=min(mi,__builtin_popcount(i));
        }

        rep(i,1,n){
            if(a[i]%100==0&&mi==4){
                _100=max(_100,a[i]/100-1);
            }
            else{
                _100=max(_100,a[i]/100);
            }
        }

       int ans2=0;
        int inf=1e9;
        rep(i,1,n){
            if(a[i]==10)ans2=1e9;
            else if(a[i]%100==10){
                ans2=max(ans2,4+(a[i]-110)/100);
            }

            if(a[i]%100==20){
                ans2=max(ans2,4+(a[i]-20)/100);
            }
            if(a[i]%100==30){
                ans2=max(ans2,inf);
            }
            if(a[i]%100==40){
                ans2=max(ans2,4+(a[i]-40)/100);
            }
            if(a[i]%100==50){
                ans2=max(ans2,4+(a[i]-50)/100);
            }
            if(a[i]%100==60){
                ans2=max(ans2,4+(a[i]-60)/100);
            }
            if(a[i]%100==70){
                ans2=max(ans2,4+(a[i]-70)/100);
            }
            if(a[i]%100==80){
                ans2=max(ans2,inf);
            }
            if(a[i]%100==90){
                ans2=max(ans2,4+(a[i]-90)/100);
            }
            if(a[i]%100==0){
                ans2=max(ans2,4+a[i]/100);
            }
        }

        printf("%d\n",min(ans2,_100+mi));
    }
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值