luoguP8764 [蓝桥杯 2021 国 BC] 二进制问题
luogu题目传送门
题目描述
小蓝最近在学习二进制。他想知道 1 到 N 中有多少个数满足其二进制表示中恰好有 K 个 1
。你能帮助他吗?
输入格式
输入一行包含两个整数 N 和 K。
输出格式
输出一个整数表示答案。
输入输出样例
输入 #1
7 2
输出 #1
3
说明/提示
对于 30% 的评测用例, ,1≤K≤10 。
对于 60% 的评测用例, ,1≤K≤30 。
对于所有评测用例, ,1≤K≤50 。
蓝桥杯 2021 国赛 B 组 H 题(C 组 J 题)。
思路
像这样时间复杂度O(N)都要超的题目显然是数位dp,只是将原来的十进制改为二进制就可以了
对于深搜的第二个参数,我们只需要定义一个sum,记录已经选了几个 1
最后退出时如果 sum 不为 k 就返回 0,否则返回 1
Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll mod=1e9+7;
ll f[205][205][2],a[205],k;
ll dfs(ll pos,ll sum,ll lim){
if(pos==0){
if(sum==k)return 1;//sum==k 才满足条件
return 0;
}
if(f[pos][sum][lim]!=-1)return f[pos][sum][lim];//如果有了就直接返回
ll ans=0;
ll en=(lim?a[pos]:1);//小细节:二进制最大为 1 ,不要打成 9
for(ll i=0;i<=en;i++){
ans+=dfs(pos-1,sum+(i==1),lim&&i==en);
}
return f[pos][sum][lim]=ans;
}
ll solve(ll x){
ll o=0;
memset(f,-1,sizeof(f));
memset(a,0,sizeof(a));
while(x>0){//将 x 转为二进制
a[++o]=x%2;
x/=2;
}
return dfs(o,0,1);
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
ll r;
cin>>r>>k;
cout<<(solve(r)-solve(0));
return 0;
}