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;
}