xjtuoj 1023:JM的祖传零钱箱
爆刷贪心ing
上来一看开个32长度数组记录下每个$2^i$分别出现了多少次,然后读入$b$后从高往低减就是了。
然后思路对了果不其然T了.
代码
//就放下中间的好了反正也T了
int n,q;
n=read();
q=read();
memset(a,0,sizeof(a));
F(i,0,n){
int w=read();
a[int(log2(w))]++;
}
//test();
F(i,0,q){
int b=read();
int ans=0;
f(i,32,-1){
int w=a[i];
int now=pow(2,i);
while(w>0&&b>=now){
b-=now;
w--;
ans++;
}
if(!b) break;
}
if(!b) cout<<ans<<endl;
else cout<<-1<<endl;
}
一看提交记录好多60分,大概都是暴力搞没搞过去
预处理一下最高位数,每次用$min(2^i\mbox{的个数},x/2^i)$算需要的个数,再用位运算去做下就好了
F(i,0,q) {
int b=read();
int ans=0;
int j;
for(j =0; (1ll<< j+1)<=b; j++); //预处理最高次,考虑到2^0所以加一,不影响后续
while(b&&j>=0) {
int t=min(a[j],b/(1ll<< j));//看是取满当前还是只需要取一部分
b-=t*(1ll<<j);
ans+=t;
j--;
}
if(!b) cout<<ans<<endl;
else cout<<-1<<endl;
}
感觉不用预处理最高位直接从$2^{32}$开始往下扫也行,