Random Task
题解
容易证明,这个n是有单调性的。证明过程如下:
当增加时,即取值区间从变到时,减少了,增加了与。
由于是的两倍,所以两者的__builtin_popcount值相等,又增加了一个。
故满足条件的数的个数只有在有个1时增加,而不会减少,且每次最多只会增加1。
于是,我们就可以通过二分n值对其求解。
至于如何求出当前n值下满足条件数的个数,可以先对其进行差分,再通过计数dp求解。
当我们在前面位数固定的情况下,后面1的个数也是固定的,设到第位前面已有位1,那么后面还需要放个1,答案即为。
于是,按位枚举一遍即可。然后就可以用的时间复杂度解决了。
源码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const double eps=1e-9;
LL m,k,C[70][70];
LL calc(LL x){
LL res=0,tot=0;
for(int i=63;i>=0;i--)
if(x&(1ll<<i)){
if(tot<=k)res+=C[i][k-tot];
tot++;
}
return res;
}
signed main(){
scanf("%lld %lld",&m,&k);C[0][0]=1;
for(int i=1;i<=64;i++){
C[i][0]=C[i][i]=1;
for(int j=1;j<i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j];
}
LL l=1,r=1e18,ans=0;
while(l<=r){
LL mid=l+r>>1ll;
if(calc(mid*2ll)-calc(mid)>=m)
ans=mid,r=mid-1ll;
else l=mid+1ll;
}
printf("%lld\n",ans);
return 0;
}