Codeforces Round #529 (Div. 3) C. Powers Of Two 进制转化

本文探讨了如何使用k个2的幂次数之和表示一个给定的整数n,通过二进制分解的方法,确定所需最小的2的幂次数目,并提供了一种算法实现,用于找到满足条件的具体数值。

题目传送
在这里插入图片描述
在这里插入图片描述
题意:给出一个n和一个k,问是否能用k个2的幂次数相加来表示。

思路:众所周知,计算机是用二进制来进行计算的。那么当然任意一个数都能表示成二进制,如9 == 1 0 0 1,那么我们很容易就知道了二进制中1的数目就是看的最小值(最少用k个数表示),最多n个数(全部是1,n个1相加为n)。那么判断YES,还是NO就搞定了。接下来就是找数了。
我们怎么找呢?很容易知道 2的3次方可以表示成2乘2的二次方,也就是两个4相加,那么我们只需要从最高位拆就是了。一直拆到k个数相加等于n即可。

AC代码

#include <bits/stdc++.h>
using namespace std;
#define NewNode (TreeNode *)malloc(sizeof(TreeNode))
#define Mem(a,b) memset(a,b,sizeof(a))
const int N = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const double EPS = 1e-10;
const unsigned long long mod = 998244353;
const int II = 3.1415926535;
typedef long long ll;
typedef unsigned long long ull;
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    ll n,k,q;
    cin >> n >> k;
    q = n;
    ll arr[50] = {0},m = 0,num1 = 0;//arr记录进制数,num1记录进制中1的个数
    while(q != 0)
    {
        arr[m++] = q % 2;
        if(q % 2 == 1)
            num1++;
        q /= 2;
    }
    if(k > n || k < num1)
        cout << "NO" << endl;
    else
    {
        int sum = num1;//已经有num1个数了
        for(int i = m-1;i >= 0;i--)
        {
            if(sum < k && arr[i] != 0)
            {
                while(arr[i])
                {
                    arr[i]--;
                    arr[i-1] += 2;//例:一个8变成了俩个4
                    sum += 1;//多一个数
                    if(sum == k)
                        break;
                }
            }
            if(sum == k)
                break;
        }
        cout << "YES" << endl;
        for(int i = m-1;i >= 0;i--)
        {
            if(arr[i] != 0)
            {
                while(arr[i]--)
                {
                    ll o = 1,k = i;
                    while(k)//这里不能直接用pow,卡了我好久,如:pow(2,29) 本来是等于536870912 ,但是计算机输出的是5.36871e+008 (换成了科学计算法)
                    {
                        o *= 2;
                        k--;
                    }
                    cout << o << " ";
                }
            }
        }
        cout << endl;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值