我看网上都是用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);
}

394

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



