Common Number(奇偶二分+找规律)

题意:给定函数f(x),x为偶数时f(x)=x/2,x为奇数时f(x)=x-1

给定n,k,对1到n每个数求f(x)的轨迹,如path[15]={15,14,7,6,3,2,1},求在所有轨迹里出现次数大于等于k的最大值ans。
思路:我们将n个数的结构画出来,就会发现这n个数组成一个树结构。把所有的数字出现的次数找出来,就会发现一个规律,由小到大,分奇偶呈现递减趋势。
例如n=14,第1 3 5 7 9 11 13的次数分别为14 6 3 2 1 1 1。第2 4 6 8 10 12 14的次数分别为13 6 3 2 2 2。那么我们就可以分别对奇偶二分,寻找最优答案。接下来最主要的就是怎么计算每个数字的次数了。
如图所示(图片摘自参考博客):
在这里插入图片描述
对于2这个点来说,出现次数=(3-2+1)+(7-4+1)+(15-8+1)+(31-16+1)。
对于5这个点来说,出现次数=(5-5+1)+(11-10+1)+(23-20+1)。
每一层的最右边点和最左边点分别呈现 上一层最右边数字2以及上一层最左边数字2+1的规律。然后配合二分,就可以了。
代码如下:

#include<bits/stdc++.h>
#define ll long long
#define inf 1e18
using namespace std;

ll n,k;
inline ll check(ll x)
{
	queue<pair<ll,ll> >p;
	if(x&1) p.push(make_pair(x,x));
	else p.push(make_pair(x,x+1));
	ll ans=0;
	while(p.size())
	{
		pair<ll,ll> zz=p.front();
		p.pop();
		ans+=min(zz.second,n)-zz.first+1;
		if((zz.first<<1)<=n) p.push(make_pair(zz.first<<1,zz.second<<1|1));
	}
	return ans;
}
int main()
{
	scanf("%lld%lld",&n,&k);
	ll l=1ll,r=(n%2)?n:n-1;
	ll ans=0;
	while(l<=r)
	{
		ll mid=l+r>>1ll;
		if((mid%2ll==0)) mid--;
		ll cnt=check(mid);
		if(cnt>=k) 
		{
			ans=max(ans,mid);
			l=mid+2ll;
		}
		else r=mid-2ll;
	}
	l=2ll,r=(n%2)?n-1:n;
	while(l<=r)
	{
		ll mid=l+r>>1ll;
		if(mid%2ll==1) mid--;
		ll cnt=check(mid);
		if(cnt>=k)
		{
			ans=max(ans,mid);
			l=mid+2ll;
		}
		else r=mid-2ll;
	}
	cout<<ans<<endl;
}

努力加油a啊,(o)/~

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值