二进制拆分+贪心——cf1303D
Posted zsben991126
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二进制拆分+贪心——cf1303D相关的知识,希望对你有一定的参考价值。
/* 先把n二进制拆分,用map保存a[i]出现次数 然后从低位到高位去凑n 对于n某位是1的位数i 考虑mp里是否有1<<i 如果没有,考虑mp里比i低位的数能否凑出i, 如果还是没有,就从高位去拆,只有这种情况下,才会对答案有贡献 */ #include<bits/stdc++.h> using namespace std; #define ll long long ll n,m,a[100005],b[65]; map<ll,ll>mp; int main(){ int t;cin>>t; while(t--){ cin>>n>>m; mp.clear(); memset(b,0,sizeof b); ll sum=0; for(int i=1;i<=m;i++) cin>>a[i],mp[a[i]]++,sum+=a[i]; for(int i=60;i>=0;i--)if((n>>i) & 1)b[i]=1; if(sum<n){puts("-1");continue;} ll ans=0; ll tot=0;//多余量 for(int i=0;i<=60;i++) if(b[i]){ if(mp[(1ll<<i)]){ mp[(1ll<<i)]--; tot+=(1ll<<i)*mp[(1ll<<i)]; mp[(1ll<<i)]=0; } else if(tot>=(1ll<<i)){//可以从多余量里凑 tot-=(1ll<<i); } else {//必须从高阶拆 ll cur=(1ll<<i); ll j=cur; while(1){ if(mp[j]!=0){ mp[j]--; break; } j<<=1; } while(j!=cur){ ans++; j>>=1; mp[j]++; } tot+=cur; } }else { tot+=mp[(1ll<<i)]*(1ll<<i); } cout<<ans<<‘ ‘; } return 0; }
以上是关于二进制拆分+贪心——cf1303D的主要内容,如果未能解决你的问题,请参考以下文章
codeforces1303D Fill The Bag 二进制应用and贪心