4941. 凑数

101 阅读2分钟

题目链接

初始时,n=0。 每一轮操作都要依次完成两个步骤:

  • 第一步,任选一个非负整数 a,将 n 增加 a,这一步所需付出的代价为 a。
  • 第二步,将 n 乘以 2,这一步无需付出任何代价。

你可以不断重复上述操作。 给定一个整数 x,你的任务是使 n 在某一步操作后(不一定是某一轮结束后)恰好等于 x 且付出的总代价尽可能少。 请你计算,为了完成任务所需付出的最小总代价。 例如,如果 x=5,则最佳操作方案为:

  • 第 1 轮操作中,第一步,将 n 增加 1(付出代价 1),使得 n 变为 1,第二步,将 n 乘以 2,使得 n 变为 2。
  • 第 2 轮操作中,第一步,将 n 增加 0(付出代价 0),则 n 仍然为 2,第二步,将 n 乘以 2,使得 n 变为 4。
  • 第 3 轮操作中,第一步,将 n 增加 1(付出代价 1),使得 n 变为 5。此时 n 等于 x 成立,任务完成。
  • 付出的最小总代价为 2。

输入格式

一个整数 x。

输出格式

一个整数,表示所需付出的最小总代价。

数据范围

前 3 个测试点满足 1x101≤x≤10
所有测试点满足 1x1091≤x≤10^9

输入样例1:

5

输出样例1:

2

输入样例2:

8

输出样例2:

1

解题思路

观察题目,题目很长,不要慌。我们由题可以得出,我们要将 n 最后变成 0。可以发现,就是求 n的二进制数中 1 的个数。n 可以由 0 向右边加若干个 0 或 1得到。乘二免费,则 n的二进制下 1 的位数为答案。

AC代码

#include<iostream> 
using namespace std;

void change(int x,int num)
{
    
     if(x==1)
    {
    	cout<<1;
        return;
    }
    int arr[100],len=0;
    while(num!=0)
    {
        arr[len]=num%x;
        len++;
        num/=x;
    }
    int cnt=0;
    for(int i=len-1;i>=0;i--)
	{
		if(arr[i]==1) cnt++;
	}
	cout<<cnt<<endl;
}
int main()
{
	int x;
	cin>>x; 
	change(2,x);
	return 0;
}