zoukankan      html  css  js  c++  java
  • [USACO13NOV]没有找零No Change 题解

    题目描述

    约翰到商场购物,他的钱包里有K(1 <= K <= 16)个硬币,面值的范围是1..100,000,000。

    约翰想按顺序买 N个物品(1 <= N <= 100,000),第i个物品需要花费c(i)块钱,(1 <= c(i) <= 10,000)。

    在依次进行的购买N个物品的过程中,约翰可以随时停下来付款,每次付款只用一个硬币,支付购买的内容是从上一次支付后开始到现在的这些所有物品(前提是该硬币足以支付这些物品的费用)。不幸的是,商场的收银机坏了,如果约翰支付的硬币面值大于所需的费用,他不会得到任何找零。

    请计算出在购买完N个物品后,约翰最多剩下多少钱。如果无法完成购买,输出-1

    输入输出格式

    输入格式:

    • Line 1: Two integers, K and N.

    • Lines 2..1+K: Each line contains the amount of money of one of FJ's coins.

    • Lines 2+K..1+N+K: These N lines contain the costs of FJ's intended purchases.

    输出格式:

    • Line 1: The maximum amount of money FJ can end up with, or -1 if FJ cannot complete all of his purchases.

    输入输出样例

    输入样例#1:

    3 6
    12
    15
    10
    6
    3
    3
    2
    3
    7

    输出样例#1: 复制

    12

    说明

    FJ has 3 coins of values 12, 15, and 10. He must make purchases in sequence of value 6, 3, 3, 2, 3, and 7.

    FJ spends his 10-unit coin on the first two purchases, then the 15-unit coin on the remaining purchases. This leaves him with the 12-unit coin.

    题目大意:

    给出k个硬币,n个商品,可以调整使用硬币的顺序,依次购买商品,每次不会找零,求最后剩下的最大钱数,如不能买全,输出-1

    因为(kleq16),考虑状压

    (dp_{sta})表示状态为(sta)时(二进制,表示哪些硬币使用了,哪些没使用),从一号物品开始能购买的物品数量

    显然有

    当使用当前状态中未使用的一个硬币时

    (dp[new\_sta]=max(dp[new\_sta],k))

    其中(new\_sta)是转移后的新状态

    (sum_k)表示前(i)个物品的总售价

    则k为(sum_k)能够支付起是的最大物品数量(最优性)

    二分一下即可求出k

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define INF 2147483647
    #define mem(i,j) memset(i,j,sizeof(i))
    #define F(i,j,n) for(register int i=j;i<=n;i++)
    #define lowbit(i) i&(-i)
    using namespace std;
    int k,n,c[20],p[100010],dp[1100000],sum[100010];
    inline int read(){
    	int datta=0;char chchc=getchar();bool okoko=0;
    	while(chchc<'0'||chchc>'9'){if(chchc=='-')okoko=1;chchc=getchar();}
    	while(chchc>='0'&&chchc<='9'){datta=datta*10+chchc-'0';chchc=getchar();}
    	return okoko?-datta:datta;
    }
    int main(){
    	k=read();n=read();
    	F(i,1,k)
    		c[i]=read(),c[0]+=c[i];
    	F(i,1,n)
    		p[i]=read(),sum[i]=sum[i-1]+p[i];
    	mem(dp,-1);
    	dp[0]=0;
    	int ans=2147483647;
    	F(sta,0,(1<<k)-1){
    		if(dp[sta]==-1)
    			continue;
    		if(dp[sta]==n){
    			int _ans=0;
    			F(i,1,k)
    				if(sta&(1<<(i-1)))
    					_ans+=c[i];
    			ans=min(ans,_ans);
    			continue;
    		}
    		F(i,1,k){
    			if(sta&(1<<(i-1)))
    				continue;
    			int l=dp[sta]+1,r=n,mid,_ans=-1;
    			while(l<=r){
    				mid=(l+r)>>1;
    				if(sum[mid]<=sum[dp[sta]]+c[i])
    					l=mid+1,_ans=mid;
    				else
    					r=mid-1;
    			}
    			if(_ans==-1)
    				continue;
    			dp[sta|(1<<(i-1))]=max(dp[sta|(1<<(i-1))],_ans);
    		}
    	}
    	printf("%d
    ",ans==2147483647?-1:c[0]-ans);
    	return 0;
    }
    
  • 相关阅读:
    纯前端导出Excel表格
    vue 组件按需引用,vue-router懒加载,vue打包优化,加载动画
    解决图片循环展示间距
    微信小程序aes前后端加密解密交互
    判断字符串中是否包含表情
    银行卡号Luhn校验算法
    身份证校验(支持15位和18位身份证号)、邮箱校验正则
    数组去重
    bootstrap 中 css 与 javascript 的使用
    js 分页
  • 原文地址:https://www.cnblogs.com/hzf29721/p/10393345.html
Copyright © 2011-2022 走看看