题目链接:点击打开链接

题意:

给定n个箱子m个物品

以下n个数字表示箱子的容量

以下m个数字b1-bm 表示物品体积为2^bi大

问最多有多少个物品能够放入箱子。

思路:

贪心,先放小的,小的不能放再放大的

显然我们把n个箱子拆成二进制,然后模拟二进制减法运算。

剩下就是简单模拟

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<set>
#include<queue>
#include<map>
#include<vector>
using namespace std;

#define ll __int64

#define N 50
ll n,_gcd,m,k;
ll a[N],b[N],er[N];
bool jie(ll pos, ll ge){
	bool hav = false;
	ll now;
	for(ll i = pos+1; i < N; i++)
		if(a[i]){
			hav = true;
			now = i;
			break;
		}
		if(hav==false)return false;
		ll ned = ge / er[now-pos];
		if(ned==0){
			a[now]--;
			a[pos]++;
			for(ll i = pos; i < now; i++)
				a[i]++;
			return true;
		}
		ned = min(ned, a[now]);
		a[now] -= ned;
		a[pos] += ned*er[now-pos];
		return true;
}
int main(){
	ll i, u;
	for(i=0, u = 1;i<N;i++, u<<=1)
		er[i] = u;
	while(cin>>n>>m) {
		memset(a, 0, sizeof a);
		memset(b, 0, sizeof b);
		while(n--){
			scanf("%I64d",&u);
			for(i=0;i<N && u>=er[i];i++){
				if(u&er[i]){
					a[i]++;
				}
			}
		}
		ll ans = 0;
		while(m--){
			scanf("%I64d",&u);
			b[u]++;
		}
		bool hav = false;
		for(i=0;i<N;i++)if(b[i]){
			while(b[i]){
				ll now = min(a[i],b[i]);
				ans += now;
				a[i]-=now;
				b[i]-=now;
				if(b[i])
				{
					if(!jie(i, b[i]))
					{
						hav = false;
						break;
					}
				}
					else break;
			}
			if(hav)break;
		}
		cout<<ans<<endl;
	}
	return 0;
}