[CF从零单排#24]【递归】743B - Chloe and the sequence

题目来源: http://codeforces.com/problemset/problem/743/B

Chloe, the same as Vladik, is a competitive programmer. She didn't have any problems to get to the olympiad like Vladik, but she was confused by the task proposed on the olympiad.

Let's consider the following algorithm of generating a sequence of integers. Initially we have a sequence consisting of a single element equal to 1. Then we perform (n - 1) steps. On each step we take the sequence we've got on the previous step, append it to the end of itself and insert in the middle the minimum positive integer we haven't used before. For example, we get the sequence [1, 2, 1] after the first step, the sequence [1, 2, 1, 3, 1, 2, 1] after the second step.

The task is to find the value of the element with index k (the elements are numbered from 1) in the obtained sequence, i. e. after (n - 1) steps.

Please help Chloe to solve the problem!

Input
The only line contains two integers n and k (1 ≤ n ≤ 50, 1 ≤ k ≤ 2^n - 1).

Output
Print single integer — the integer at the k-th position in the obtained sequence.

Examples
input
3 2
output
2
input
4 8
output
4
Note
In the first sample the obtained sequence is [1, 2, 1, 3, 1, 2, 1]. The number on the second position is 2.

In the second sample the obtained sequence is [1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1]. The number on the eighth position is 4.

题目大意:

有这样一个序列,它是会动态变化的。第一轮时它只有一个数{1}, 后面一轮是这样构成的{【前一轮】,不小于前面数的最小值,【前一轮】} ,所以第二轮时,它变成了{1,2,1}, 第三轮变成了{1,2,1,3,1,2,1}。现在给出两个整数n,k。求第n轮时,第k个位置的数是多少?(k从1开始计算)。

题目分析:

简单分析一下,序列是成倍增长,如果用数组来储存,n<=50,2^50肯定会爆空间,所以要考虑其他方法。考虑第i轮与第i-1轮的关系,我们可以发现,其实规模是逐渐减小的,假设第i轮中间位置是t,那么第i轮中间的位置上的数就是i,左边和右边是相同的。所以我们可以考虑用递归的方式来不断缩小范围。那么我们就需要考虑k的位置,如果k=t, 显然不需要递归下去了,答案就是i。如果k>t,那么显然是在右边,又因为左半部分和右半部分完全相同,所以k位置的数与k-t位置的数完全相同。如果k<t,那显然就是左边位置。那么我们只需要设一个递归函数f(i,k)就可以完成了。

参考代码:

#include <bits/stdc++.h>
using namespace std;

long long fun(int x, int p){ // 计算x^p 
	long long s = 1;
	for(int i=1; i<=p; i++)
		s *= x;
	return s;
}

int f(long long n, long long k){
	if(n==1)  // 递归边界 
		return 1;
	long long t = fun(2, n-1);  //中间位置 
	if(k==t)  // 中间数 
		return n;
	if(k>t)  // 右边, 返回上一轮,且左右是对称 
		return f(n-1, k-t);
	else    // 左边,返回上一轮 
		return f(n-1, k); 
}

int main(){
	long long n, k;
	cin >> n >> k;
	cout << f(n, k);
	return 0;
}
posted @ 2020-08-12 16:42  gdgzliu  阅读(197)  评论(0编辑  收藏  举报