题意:
给的m和k,找到一个n,使得区间[n+1,2*n]里的数中,恰好有m个数满足要求:该数的二进制表示里恰好有k个1.
题解:
在k相同的情况下,n单调,可以二分。
重点是求出某个区间满足要求的数的个数。
我们设cal(x)为区间[0,x]中,二进制表示中1个个数为k的数的个数,那么对于一个二分的答案Mid,对应的[Mid+1,2*Mid]满足要求的数的个数为cal(2*Mid)-cal(Mid).
例如二进制x=101101 k=3
扫描二维码关注公众号,回复:
4327819 查看本文章
从高位到底为枚举每一位i:第一位为1,将其置0后,后面可以有任意k个1,故res+=Com(i,k-cnt),Com为组合数,cnt为该位前面的1的个数。第2位为0,跳过;第3位为1,
将该置0,则前面有2个1被置0,则后面还要添加k-2个1。res+=Com(i,k-2),依次计算。
/****************
*PID:431d div2
*Auth:Jonariguez
*****************
*/
#define lson k*2,l,m
#define rson k*2+1,m+1,r
#define rep(i,s,e) for(i=(s);i<=(e);i++)
#define For(j,s,e) For(j=(s);j<(e);j++)
#define sc(x) scanf("%d",&x)
#define In(x) scanf("%I64d",&x)
#define pf(x) printf("%d",x)
#define pfn(x) printf("%d\n",(x))
#define Pf(x) printf("%I64d",(x))
#define Pfn(x) printf("%I64d\n",(x))
#define Pc printf(" ")
#define PY puts("YES")
#define PN puts("NO")
#include <stdio.h>
#include <string.h>
#include <string>
#include <math.h>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef int Ll;
Ll quick_pow(Ll a,Ll b,Ll MOD){a%=MOD;Ll res=1;while(b){if(b&1)res=(res*a)%MOD;b/=2;a=(a*a)%MOD;}return res;}
const int maxn=100000+10;
LL m,k;
LL Com(LL n,LL m){
if(m==0) return 1LL;
LL res=n--,i;
for(i=2;i<=m;i++){
res*=n;res/=i;
n--;
}
return res;
}
LL cal(LL n){
LL res=0,i,cnt=0;
for(i=62;i>=0;i--){
if((n>>i)&1){
if(k-cnt>=0)
res+=Com(i,k-cnt);
cnt++;
}
}
return res;
}
int main()
{
int i,j;
while(scanf("%I64d%I64d",&m,&k)!=EOF){
LL l=1,r=1e18,Mid,res=-1;
while(l<r-1){
Mid=l+(r-l)/2;
LL temp=cal(2*Mid)-cal(Mid);
if(temp==m){
res=Mid;break;
}else if(temp<m)
l=Mid+1;
else r=Mid;
}
// printf("cal=%I64d\n",cal(2));
if(res>=0)
printf("%I64d\n",res);
else printf("%I64d\n",l);
}
return 0;
}