CF896A Nephren gives a riddle

做dp做自闭了 写一题毒瘤题放松一下
题意:

对于以下生成字符串规则

\[\begin{array} \ f(0)\ =\ What\ are\ you\ doing\ at\ the\ end\ of\ the\ world?\ Are\ you\ busy?\ Will\ you\ save\ us?\\ f(n)\ =\ What\ are\ you\ doing\ while\ sending\ "f(n\ -\ 1)"?\ Are\ you\ busy?\ Will\ you\ send\ "f(n\ -\ 1)"?,\ n\ >=\ 1 \end{array} \]

输出第n个字符串中的第k个字符,多组输入。

\[\begin{array} \ a = f(0),\\ b=What\ are\ you\ doing\ while\ sending\ "\\ c = "?\ Are\ you\ busy?\ Will\ you\ send\ "\\ d = "?\\ \end{array} \]

即f(0) = a, f(1) = bacad, f(2) = b(bacad)c(bacad)d, ...

f(n)的结构:b(f(n - 1))c(f(n - 1))d

\(f(n)\)的长度就可以求得为\(f(n - 1)\)的长度*2 + bcd的长度

n = 0时,可直接判断第k个字符

对于任意一个n(>=1),f(n)的第k个位置,只要k满足<= b的长度,那么对应的字符就是b[k - 1]

对于一个n(>= 1),并且k的长度 > b的长度,就需要用递归简化问题了

但是注意本题n的范围非常大,最大值为1e5,如果要判断k所在的位置,就需要计算\(f(1e5)\)各个部分的长度,\(f(1e5)\)的长度为\(2^{1e5}a2^{1e5-1}(b+c+d)\)的长度,什么数据结构都存不下,也别想用大整数,因为那样复杂度会爆炸。

此时注意到k的最大值为1e18, 而当n = 53的时候,发现f(n)的长度已经大于1e18了,这就说明n >= 54(b(f(n - 1))c(f(n - 1))d)的时候,k一定位于红色部分,所以所有大于53的n均可以被减小到53再处理,然后不断减小问题规模。

代码:

#include<iostream>
#include<string>

using namespace std;

#define LL long long

const int N = 54;

LL len[N];

string str[] ={
    "What are you doing at the end of the world? Are you busy? Will you save us?",
    "What are you doing while sending \"",
    "\"? Are you busy? Will you send \"",
    "\"?"
};

int q;
int a, b, c, d;

char find(int n, LL k){
    if(n == 0)
        if(k <= a) return str[0][k - 1];
        else return '.';
        
    if(k <= b) return str[1][k - 1];
	
    if(n >= 54) return find(n - 1, k - b);
    
    LL p1 = b + len[n - 1], p2 = p1 + c, p3 = p2 + len[n - 1];
    
    if(k <= p1) return find(n - 1, k - b);
    if(k <= p2) return str[2][k - p1 - 1];
    if(k <= p3) return find(n - 1, k - p2);
    if(k - p3 <= d) return str[3][k - p3 - 1];
    return '.';
}

int main(){
    
    a = str[0].size(), 
    b = str[1].size(), 
    c = str[2].size(), 
    d = str[3].size();

    for(int i = 0; i < N; i ++)
        if(i) len[i] = len[i - 1] * 2 + b + c + d;
        else len[i] = a;
    
    cin >> q;
    
    while(q --){
        int n;
        LL k;
        
        cin >> n >> k;
        
        cout << find(n, k);
    }

    return 0;
}

posted @ 2021-01-28 18:00  yys_c  阅读(312)  评论(0编辑  收藏  举报