8.二进制问题 - 蓝桥云课
存入N的二进制每一位作为基准数组 算出方案数
从高位往低位用dfs枚举每一位是放1还是放0
#include<iostream>
#include<vector>
#define ll long long
using namespace std;
ll dp[65][65];
ll num;
ll k;
vector<ll> vec;
ll cal(ll n,ll k){
if(dp[n][k]) return dp[n][k]; //记忆化搜索 如果已经处理过 直接返回C(n,k)
if(n==k) return 1;//C(n,n) = 1;
if(k==0) return 1;//C(n,0) = 1;
if(n<k) return 0;//n不够位置给K放 直接返回 0
return dp[n][k]=cal(n-1,k-1)+cal(n-1,k);
//n里面选k个位置放1 等于当前位置放1 + 当前位置不放1 的方案数的总和 递归计算
}
ll dfs(int pos,int last){
//last 已经放置的K的个数
//pos当前处理到哪一位了
//出口
if(last==k) return 1;
if(pos<0||last>k)return 0;
ll res=0;
if(vec[pos]==1){
//如果当前位置为 1 可以选择放 1 或者放 0
res+=cal(pos,k-last); // 如果选则放0 还剩下pos个位置 (初始一共pos+1个位置 0 到pos)
// 这pos个位置随意选k-last个1 所以直接用组合数加上
res+=dfs(pos-1,last+1);//当前位置放1 处理下一位
}
else res+=dfs(pos-1,last);//当前位置不为1,保持与原数二进制相等 继续处理下一位
return res;
}
int main(){
scanf("%lld %d",&num,&k);
while(num){
vec.push_back(num%2);
num/=2;
}
//vec.size() 二进制的位数
//vec.size()-1 最高位的索引
cout<<endl;
ll ans=dfs(vec.size()-1,0);
cout<<ans<<'\n';
return 0;
}
cal函数的可以算出组合数的原因来自于杨辉三角
由顶层的1 可以加出下面的组合数