XJTUOJ #1023 JM的祖传零钱箱

题目描述

JM的太爷爷的太爷爷的太爷爷……的太爷爷喜欢攒零钱,并把攒零钱作为祖训传承至今,现在已经攒了整整一箱子的硬币,JM清点了一下发现箱子里一共有\(n\)枚硬币。众所周知,古代的钱币放到现在都很值钱,所以这些硬币的价值并不相同。不过,由于寒域爷施了石志魔法,这些硬币的价值都是\(2\)的幂次。也就是说,对于任意的第\(i\)枚硬币,其价值\(a_i\)一定满足\(a_i=2^d\),其中\(d\)是某个非负整数。

现在,石乐志的JM想拿这些硬币去买菜,他有\(q\)种想买的菜。因为石乐志,JM认为硬币的价值并不重要,而硬币的数量是最重要的。所以在买菜之前,他想事先知道,对于每种价格为\(b_j\)的菜,他最少需要用掉多少枚硬币才能将其买下。另外,由于JM有强迫症,他不希望他在买菜的时候还需要找零。

他希望你帮他分别计算买这\(q\)种菜的所需硬币数。注意,是分别计算,每种菜的求解之间是互相独立的。

输入格式

第一行两个正整数\(n\)\(q\),表示JM的硬币数和JM想买的菜的种类数。

接下来一行\(n\)个正整数\(a_i\),表示每个硬币的价值。输入保证\(a_i=2^d\),其中\(d\)是某个非负整数。

接下来\(q\)行,每行一个正整数\(b_j\),表示每种菜的价格。

输出格式

输出\(q\)行,每行一个正整数,表示买下每种菜所需的最少硬币个数。如果无论如何也无法凑齐价格(注意不能找零),则输出\(-1\)

数据范围

\(1\leq n,q \leq 2*10^5\)

\(1\leq a_i,b_j \leq 2*10^9\)

思路

存储:我们可以令\(a[i]\)表示面值为\(2^i\)的硬币有多少枚。

这是一道贪心题,对于每一个\(x\),我们从2的高次幂往低次扫,能取就尽量取完。比如现在硬币面额为\(2^i\),所取的数量\(t\)应为满足\(t\leq a[i]\)\(t*2^i\leq x\) 的最大值。

如果这样取最终能使x归零,那么有解,且最优取法如上;否则无解。

为什么呢?因为低次幂可以拼成高次幂,而高次幂无法拆成低次幂。所以我们优先把高次幂取掉,既减少了所用硬币数量,又留下更多灵活的小面额给接下来的步骤。(感性理解一下)

注意:题目所给的数据范围很接近int的最大值,小心溢出。

代码

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
int a[30];
int main(){
	int i,j,n,m,x,ans;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		int t=-1;
		scanf("%d",&x);
		while(x){
			x>>=1;
			t++;
		}
		a[t]++;
	}
	for(i=1;i<=m;i++){
		scanf("%d",&x);
		ans=0;
		for(j=0;(1ll<<j+1)<=x;j++){
		}
		while(x&&j>=0){
			int t=min(a[j],x/(1<<j));
			x-=t*(1ll<<j);
			ans+=t;
			j--;
		}
		if(!x) printf("%d\n",ans);
		else printf("-1\n");
	}
	return 0;
}
posted @ 2020-10-13 15:58  文艺平衡树  阅读(81)  评论(2编辑  收藏  举报