蓝桥杯-二进制问题

我看网上都是用dp来做的这道题,我提供个不一样的方法吧

首先思考如果二进制数n上每一位都是1,如1111,然后k=2,那么显然结果就是c(4,2),

两个1可以放在四位中的任意位置,

如果n不全为1,如10101,k=2

那么11000就不满足情况了,因为形成的数字大于n了

但是可以放在后四位的任意位置,最高位为0,肯定都符合情况,

此时结果可以先加上个c(4,2)

再考虑最高位为1的情况

当最高位放了1,那么k变成1,此时最高位不必再考虑,干脆给它去掉,即n变成101,

然后运用相同的思路,最后一个1不放在最高位,结果加上c(2,1)

放在最高位,k变成0,n变成1,显然这样只有一种情况,返回1

最终加在一起答案是9

#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;

ll c(ll a,ll b)//计算组合数
{
	ll res=1;
	for(int i=1;i<=a;i++)
		res=res*(b-a+i)/i;
	return res;
}
ll f(ll n,ll k)
{
	ll x=(log(n)/log(2)+1);//计算当前数值所需的最少二进制位数
	if(pow(2,k)-1==n||k==0)//当n的二进制形式全是1且所要安置的1的个数等于x,
                           //或者需要放置的1的个数k==0时,那么只有一种情况,返回1
		return 1;	
	if(x<=k)//总位数小于k的个数返回0
		return 0;	
	return c(k,x-1)+f(n-pow(2,x-1),k-1);//当k<x,递归的计算
}                                       //c()计算所有的1放在最高位之后的情,即最高位不放1
                                        //f()计算将一个1放在最高位,其余k-1个数放在低位
                                                                       
int main()                    
{
	ll n,k;
	cin>>n>>k;
	cout<<f(n,k);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值