题目传送


题意:给出一个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;
}
}
本文探讨了如何使用k个2的幂次数之和表示一个给定的整数n,通过二进制分解的方法,确定所需最小的2的幂次数目,并提供了一种算法实现,用于找到满足条件的具体数值。
407

被折叠的 条评论
为什么被折叠?



