1. 程式人生 > >福州大學第十五屆程式設計競賽 G

福州大學第十五屆程式設計競賽 G

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<T<=10 0<n<=100 0<k<=1000000000且保證位置k一定有字元


Output
每組測試資料輸出第n代第k個位置的字元


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

U

思路:和之前校賽的那個題目類似,但是由於在火車這個題目沒有細看,原來是一道很水的遞迴題目。

直接列舉是不太現實的,會TLE,所以要巧妙的遞迴,由於是父代生子代,所以我們可以計算出每一代字元有多少個,然後通過長度來不斷縮小字元的範圍,最後確定結果,一個細節是當n=24時,字元數量已經為1e9了。

詳情看程式碼      

#include<cstdio>
#include<algorithm>
#include<cstring>
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;
}