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