CodeForces - 815E - Karen and Neighborhood

E. Karen and Neighborhood
time limit per test
2 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

It's been long after the events of the previous problems, and Karen has now moved on from student life and is looking to relocate to a new neighborhood.

The neighborhood consists of n houses in a straight line, labelled 1 to n from left to right, all an equal distance apart.

Everyone in this neighborhood loves peace and quiet. Because of this, whenever a new person moves into the neighborhood, he or she always chooses the house whose minimum distance to any occupied house is maximized. If there are multiple houses with the maximum possible minimum distance, he or she chooses the leftmost one.

Note that the first person to arrive always moves into house 1.

Karen is the k-th person to enter this neighborhood. If everyone, including herself, follows this rule, which house will she move into?

Input

The first and only line of input contains two integers, n and k (1 ≤ k ≤ n ≤ 1018), describing the number of houses in the neighborhood, and that Karen was the k-th person to move in, respectively.

Output

Output a single integer on a line by itself, the label of the house Karen will move into.

Examples
input
6 4
output
2
input
39 3
output
20
Note

In the first test case, there are 6 houses in the neighborhood, and Karen is the fourth person to move in:

  1. The first person moves into house 1.
  2. The second person moves into house 6.
  3. The third person moves into house 3.
  4. The fourth person moves into house 2.

In the second test case, there are 39 houses in the neighborhood, and Karen is the third person to move in:

  1. The first person moves into house 1.
  2. The second person moves into house 39.
  3. The third person moves into house 20.


题目大意:

有n个房屋一字排开,并从左至右编号为1, 2, …, n。有k个人陆续入住,每个人会挑选无人住的房屋,如果有多间可以选择,那么选择离已有人住的房屋最远的那一间(不是总距离最远哦,如果还有多个选择,选择编号最小的。

第一个人永远会住进第一间,问最后一个人会住进哪间屋子。

题解:

显然第2个人会住进最后一间,算是一个特例,在这之后,有人住的屋子会把剩余的分成多个区间,下一个人入住时,会选择一个区间中间的房屋入住。

解这题的时候绕了很多弯路,比如一开始试图找到一个优雅的公式去解题,比如像二分一样,若有a个人要在一个区间里选房子住,第一个一定是住中间,然后区间被分为两个,剩余的人先左边住1个,右边住一个,再左边住两个,右边住两个,再左边住四个……这样就能确定最后一个人会住进哪一边,并且有几个人也选择了那一侧,再缩小范围继续算,结果发现有很多意外情况,加了各种if else后,才发现这个思路就不对。

后来还是用一个很暴力直接的方法过了这题,而且不慢也不复杂,至少比上面的各种if else还要优雅:

  1. 每次入住的时候,假设现在有x个区间,因为想找一个离别人尽量远的,所以一定会选择(x+1)/2尽量大的区间(为什么不是x?这是个坑,你想想),如果有多个,就选择编号最小的
  2. 入住之后,区间会被分成两个(除非原区间长度小于等于2),所以任意时刻,区间的长度最多四种。
  3. 按照区间的长度归类,每次可以批量让一群人入住到一种长度的区间中,每个区间住一个,这样区间的数量成指数级增长,很快人就都能住完。
  4. 如果将区间分为左右两种后,再分别按3归类,那么最后就能判断出最后一个人进入了哪边的区间,且还有几个人进入了那边的区间,递归。
ac代码:
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
	char c=getchar();int p=1,ret=0;
	while((c<'0')||(c>'9')){if(c=='-')p=-1;c=getchar();}
	while((c>='0')&&(c<='9'))ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ret*p;
}
long long n,k;
long long s[2],p[2];
long long get(long long now,long long to){
	if(now<=to*2)return 0;
	long long re=0;
	s[0]=1;s[1]=0;
	p[0]=now;p[1]=now-1;
	while(p[1]>=to*2){
		if(p[1]==to*2)return s[0]+re;
		if(p[0]&1){
			re+=s[0]+s[1];
			s[0]=s[0]*2+s[1];
			p[1]=p[0]/2-1;p[0]=p[0]/2;
		}else{
			re+=s[0]+s[1];
			s[1]=s[1]*2+s[0];
			p[1]=p[0]/2-1;p[0]=p[0]/2;
		}
	}
	return re;
}
inline long long solve(long long l,long long r,long long p,long long k){
	long long mid=(l+r)/2;
	if(k==1)return mid;
	long long tmp=get(mid-l,p),Tmp=get(r-mid,p+1); 
	if(k>tmp+Tmp+1)return solve(mid+1,r,p,k-tmp-1);
	else return solve(l,mid-1,p,k-Tmp-1);
}
int main(){
	scanf("%I64d%I64d",&n,&k);
	if(k<=2){printf("%I64d",k==1?1:n);return 0;}
	n-=2;k-=2;
	long long l=0,r=n/2+1;
	while(r-l>1){
		long long mid=(l+r)/2;
		if(get(n,mid)<k)r=mid;
		else l=mid;
	}
	printf("%I64d",solve(1,n,l,k)+1);
}

题目链接: 点击打开链接http://codeforces.com/problemset/problem/815/E


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值