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