codeforces_916B

题意:给定n,n是由一系列数的和组成,这些数是2^a,2^b,2^c。。。。最多有k个,你的目的是让a,b,c….中最大的数最小,如果这样的数列有多个,输出字典序最大的那个。
思路:二进制之所以唯一是因为它的每一个二进制位都只能使用一次,比如23=2^4+2^2+2^1+2^0,二进制在每位都使用一次且保证最大的数最小的情况下,去唯一的表示了一个数,那么我们假设每个二进制位能用无数多次,那么每个数可以表示成无数多种,比如23=2^3+2^3+2^2+2^1+2^0还有23=2^2*5+2^1+2^0,这样最高位就越靠左,好了,不扯了。
现在看看本题:跟上面说的一样,此题相比较上面的理论,唯一不同在于使用的数有限制,数的个数不能超过k,比如第一个样例,不能超过5个,那么23=(2^2)*5+2^1+2^0显然不符合要求,因为2就已经被使用了5次,再思考一个问题,最高位拓展到次高位需要花费的次数是多少呢,是最高位当前被使用过的次数,如果说最高位的使用次数已经超过了当前剩余可使用数的个数k,那么就从最低位开始去利用剩下的可使用数把低位摊分,来保证字典序最大。

#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
#define inf 0x7ffffffffff
typedef long long ll;
int main()
{
    ll n,k,m=0;
    map<int,int> cnt;
    cnt.clear();
    cin>>n>>k;
    int now;
     while(n>0){
        cnt[m]=n&1;
        n>>=1;
        if(cnt[m++]) {k--;now=m-1;}
    }
    if(k<0) {cout<<"NO"<<endl;return 0;}
    while(cnt[now]<=k){
        cnt[now-1]+=cnt[now]*2;
        k-=cnt[now];
        cnt[now]=0;
        now--;
    }
    int cur=min(now,0);
    for(cur;cur<m;cur++) if(cnt[cur]) break;
    while(k){
         if(cnt[cur]) {
             cnt[cur-1]+=2;
             cnt[cur]--;
             k--;
         }
         cur--;
    }
    cout<<"Yes"<<endl;
    for(int i=m-1;i>=cur;i--){
         for(int j=0;j<cnt[i];j++) cout<<i<<" ";
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值