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;
}