1. 程式人生 > 實用技巧 >[CF從零單排#24]【遞迴】743B - Chloe and the sequence

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