codeforces1303D Fill The Bag

https://codeforces.com/problemset/problem/1303/D

先把所有数字放进num[0-62],表示2^i有多少个

然后对于n的二进制表示从小到大考虑,如果num[i]有剩余,那么num[i+1]+=num[i]/2

如果某个时刻n>>i&1,但是num[i]=0,则需要去min(j)(j>i && num[j]>0)那个位置,把一个2^j一直拆到2^i

找不到就ans=-1,

因为找到第一个j没有break WA了4发。。。天崩

 

#include<bits/stdc++.h>
using namespace std;

const int maxl=3e5+10;

int m,ans;
long long n,sum;
long long num[64];
long long a[maxl];
char s[maxl];

inline void prework()
{
	for(int i=0;i<63;i++)
		num[i]=0;
	sum=0;ans=0;
	long long x;
	scanf("%lld%d",&n,&m);
	for(int i=1;i<=m;i++)
	{	
		scanf("%lld",&a[i]);
		sum+=a[i];x=a[i];
		for(int j=0;j<63;j++)
		{
			if(x&1)
				num[j]++;
			x>>=1;
		}
	}
}

inline void mainwork()
{
	if(sum<n)
	{
		ans=-1;
		return;
	}ans=0;
	long long x=n,d;
	for(int i=0;i<63;i++)
	{
		if(x&1)
		{
			if(num[i]==0)
			{
				for(int j=i+1;j<63;j++)
				if(num[j]>0)
				{
					num[j]--;
					for(int k=j-1;k>=i+1;k--)
						num[k]++;
					num[i]+=2;ans+=j-i;
					break;
				}
				if(num[i]==0)
				{
					ans=-1;
					return;
				} 
			}
			num[i]--;
		}
		x>>=1;
		num[i+1]+=num[i]/2;
	}
}

inline void print()
{
	printf("%d\n",ans);
}

int main()
{
	int t=1;
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值