福州大学第十五届程序设计竞赛 G - FZU FZU - 2290

Silchen有一个第1代字符串"FZU",现在定义一个下一代生成如下


字符'F'可以生成字符串"FZU"


字符'Z'可以生成字符串"FZ"


字符'U'可以生成字符串"FU"


例如:


第1代是"FZU"


第2代是"FZUFZFU"


第3代是"FZUFZFUFZUFZFZUFU"


Silchen想知道第n代的第k个位置的字符是什么


Input
题目包含多组测试数据,每组测试数据第一行是T表示组数


接下来有T行


每行两个整数n, k,表示Silchen想知道第n代第k个位置的字符是什么


0

Output
每组测试数据输出第n代第k个位置的字符


Sample Input
3
1 1
2 5
3 3
Sample Output
F
Z

U

思路:和之前校赛的那个题目类似,但是由于在火车这个题目没有细看,原来是一道很水的递归题目。

直接枚举是不太现实的,会TLE,所以要巧妙的递归,由于是父代生子代,所以我们可以计算出每一代字符有多少个,然后通过长度来不断缩小字符的范围,最后确定结果,一个细节是当n=24时,字符数量已经为1e9了。

详情看代码      

#include
#include
#include
using namespace std;
const int maxn = 1e5 + 5;
int f[105], n, k;
char solve(int l, int r, int step, int flag)
{
    if(step == n + 1)
    { 
        if(flag == 1) return 'F';   //第一部分
        if(flag == 2) return 'Z';   //第二部分
        return 'U';                 //第三部分
    }
    if(flag == 1)
    {
        int a = f[n-step], b = (r - l + 1 - f[n-step]) / 2;//a为确定第一部分的位置 b为确定第二部分的位置
        if(k < l + a) return solve(l, a + l - 1, step + 1, 1); //属于第一部分的内容
        else if(k < l + a + b) return solve(l + a, l + a + b - 1, step + 1, 2);//属于第二部分的内容
        else return solve(l + a + b, r, step + 1, 3);//属于第三部分的内容
    }
    else
    {
        int a = f[n-step], b = r - l + 1 - f[n-step];
        if(k < l + a) return solve(l, a + l - 1, step + 1, 1);
        else return solve(a + l, r, step + 1, flag);
    }
}

int main()
{
    f[0] = 1; f[1] = 3;
    for(int i = 2; i <= 24; i++) f[i] = 2 * f[i-1] + f[i-2];//计算每一层的字符数量
    int T;
    while(scanf("%d", &T) == 1){
        while(T--){
            scanf("%d%d", &n, &k);
            if(n > 24) n = 24;
            char ch = solve(1, f[n], 1, 1);
            printf("%c\n", ch);
        }
    }
    return 0;
}

你可能感兴趣的:(ACM_递推,FZU)