目录
问题描述
设A=“^__^”(4个字符),B=“T.T”(三个字符),然后以AB为基础,构造无限长的字符串,重复规则如下:
(1)把A接在B的后面构成新的字符串C。例如,A=“^__^”,B=“T.T”,则C=BA=“T.T^__^”。
(2)令A=B,B=C,如上例所示,则A=“T.T”,B=“T.T^__^”。
编程任务:给出此无限长字符串中的第n个字符。
输入
输入有多组测试例。每个测试例只有一个整数N,其中。
输出
对每个测试例输出一行,是此无限长字符串中的第N个字符(序号从1开始).
输入样例
1
2
4
8
输出样例
T
.
^
T
算法分析
本题看起来很简单,字符串的组合也很有规律,有的读者就试图研究叠加后的字符串规律。结果发现,叠加后的字符串虽然有规律,但是与输入的数据n之间没有直接的联系。
1.从字符串的长度研究字符串生成规律
a=strlen("^__^") ->a=4
b=strlen("T.T") ->b=3
c=strlen("T.T^__^") ->c=7
再按照题目给定的步骤重复,就很容易发现,这正是以a,b为基数的斐波那契(Fibonacci)数列。
对于输入的正整数n,它位于经过若干次按斐波那契数列的规律叠加后的字符串中。无论它如何叠加,该位置的字符总是在字符串C中。本题就变成给定一个正整数n,求出小于n的最大斐波那契数,n与该斐波那契数的差正是该字符在字符串C中的位置。
输出时要注意,字符串的位置是从0开始编号的,所以用这个差值当下标时需要减去1。
2.算法优化
由于n最大可达,对于输入的每个n,都去计算小于n的最大斐波那契数,显然是非常浪费时间的。解决的办法是预先把在 范围内的所有斐波那契数求出来,放到一个数组中。经过测算,该斐波那契数列最多为86项,第86项的斐波那契数约是,而约是,如下所示。
算法:
#define LEN 88
string base=="T.T^__^";
//将斐波那契(Fibonacci)数列在2^63-1范围之内的数全部计算出来
long long int f[LEN];
f[0] = 7;f[1] = 10;
for(int i = 2;i < LEN;i++)
f[i] = f[i-1] + f[i-2];
long long int n;
while(cin>>n)
{
//对于每一个n,减去小于n的最大斐波那契数
while(n > 7)
{
int i=0;
while(i < LEN&& f[i] < n)
i++;
n-=f[i-1];
}
//n中剩下的值,就是该字符在base中的位置
cout<<base[n-1]<<endl;
}
转载地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1633