习题10-23 Hendrie序列 UVa10479

来源:互联网 发布:海报设计制作软件 编辑:程序博客网 时间:2024/04/29 15:59

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 64typedef 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;}

0 1
原创粉丝点击