习题10-23 Hendrie序列 UVa10479

1.题目描述:点击打开链接

2.解题思路:本题是一道找规律题,仔细观察后发现有以下特点:

(1)下标为2^k的数正好为k(下标从1开始)。

(2)如果依次以1,2,4,8...的长度来分解串,可以将序列分解为:0 1 02 1003 02110004 1003020211100005......可以发现,第i个串是由第i-2,i-3,...2,1,0个串组成的。且第i-2个串有1个,第i-3个串有2个,第i-4个串有3个......第1个串有i-2个,第0个串有i-1个,最后再加上数字i。也就是是说,串的构造时递归的。因此可以考虑递归求解。

好了,观察出来上述两个特点后,就可以顺利解决本题了。首先利用第一个性质,将所有的坐标初始化,放到pos数组。由于最高可达2^63,因此应该使用unsigned long long类型。同时初始化第i个串的长度为num[i]。

接下来,每次输入一个n,先查找刚刚大于n的位置pos[i],令len=pos[i]-n,接下来利用第二个特点递归求解,即dfs(len,i)。返回的是len==0时候对应的数字。根据性质2,从第0个串开始考虑(当前考虑的串设为now),如果len超过了i*num[now](i表示第now个串的个数),那么len-=i*num[now],同时now++。这样一直到长度<i*num[now]为止.由于第now个串的构造也是递归的,因此可以递归求解,即dfs(len,now)。不过事先应取模,即len=(len-1)%num[now]。因为我们只考虑len<=num[now]的情况。

3.代码:

#define _CRT_SECURE_NO_WARNINGS 
#include<iostream>
#include<algorithm>
#include<string>
#include<sstream>
#include<set>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<functional>
using namespace std;

#define maxn 64
typedef unsigned long long ull;
ull pos[maxn], num[maxn];

void init() 
{
	num[0] = num[1] = 1;
	for (int i = 2; i < maxn; i++)
		num[i] = num[i - 1] * 2;//num[i]表示第i个串的长度
	pos[1] = 2;
	for (int i = 2; i < maxn; i++)
		pos[i] = pos[i - 1] * 2;//标记i首次出现时的下标(从1开始)
}

int dfs(ull len, int n) 
{
	if (len == 0) return n;
	int now = 0;
	for (int i = n - 1; i > 0; i--) 
	{
		if (len > i * num[now])
			len -= i * num[now];
		else 
		{
			if (now == 0 || now == 1)  
				return now;
			len = (len - 1) % num[now];//将len修改为一个num[now]内的长度
			return dfs(len, now);//递归求解
		}
		now++;
	}
}

int main() 
{
	//freopen("t.txt", "r", stdin);
	init();
	long long n;
	while (scanf("%lld", &n) == 1 && n) 
	{
		if (n == 1) 
		{
			printf("0\n");
			continue;
		}
		for (int i = 1; i <= 64; i++) 
		{
			if (n <= pos[i]) //先找到刚刚超过n的i
			{
				printf("%d\n", dfs(pos[i] - n, i));//利用dfs求解
				break;
			}
		}
	}
	return 0;
}

你可能感兴趣的:(DFS,找规律)