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}$开始往下扫也行,

posted @ 2022-04-07 20:48  FPICZEIT  阅读(4)  评论(0编辑  收藏  举报