这其实就是一道基础的数位DP题,如果对这方面知识有了解的同学可能就能直接做出来,如果不知道什么是数位DP的同学可以看这里:数位DP模板详解_AC__dream的博客-CSDN博客
显然我们f数组中只需要存下当前位pos以及遍历到当前位有多少个1,由于这道题的结果是与0无关的,所以也就不需要考虑前导0了,直接当pos位变为0时返回就行了,如果遍历到最后一位当前1的个数是k个就返回1,否则返回0,在过程中如果出现1的次数大于k可以直接剪掉。
别的就没什么好说的了,下面是代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=63;
long long f[N][N];
int a[N];
int k;
long long dfs(int pos,int cnt,int limit)
{
if(!pos) return cnt==k;
if(!limit&&f[pos][cnt]!=-1) return f[pos][cnt];
int up=limit?a[pos]:1;
long long ans=0;
for(int i=0;i<=up;i++)
ans+=dfs(pos-1,cnt+(i==1),limit&&(i==up));
if(!limit) f[pos][cnt]=ans;
return ans;
}
long long solve(long long x)
{
int pos=0;
memset(f,-1,sizeof f);
while(x)
{
a[++pos]=x%2;
x/=2;
}
return dfs(pos,0,1);
}
int main()
{
long long n;
cin>>n>>k;
cout<<solve(n);
return 0;
}