[CF431D]Random Task

Random Task

题解

容易证明,这个n是有单调性的。证明过程如下:

n增加时,即取值区间从[n+1,2n]变到[n+2,2n+2]时,减少了n+1,增加了2n+12n+2

由于2n+2n+1的两倍,所以两者的__builtin_popcount值相等,又增加了一个2n+1

故满足条件的数的个数只有在2n+1k个1时增加,而不会减少,且每次最多只会增加1。

于是,我们就可以通过二分n值对其求解。

至于如何求出当前n值下满足条件数的个数,可以先对其进行差分,再通过计数dp求解。

当我们在前面位数固定的情况下,后面1的个数也是固定的,设到第i位前面已有j位1,那么后面还需要放k-j个1,答案即为C_{len-i}^{k-j}

于是,按位枚举一遍即可。然后就可以用O\left(nlog_{n} \right )的时间复杂度解决了。

源码

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

谢谢!!!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值