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; }
时间: 2024-10-09 20:54:29