题解:AT_abc242_d [ABC242D] ABC Transform

其实这道题还是挺简单的。

怎么说呢,看到这道题的后我瞬间就想到了分治和二叉树(主要是因为一个字母可以分成两个字母),于是我就写了个 dfs,但有个问题:题目给的数据范围是 0 ≤ t i ≤ 1 0 18 0\le t_i\le10^{18} 0ti1018,而写二叉树则是一层一层往上跑,这不就成了 O ( 1 0 18 ) O(10^{18}) O(1018) 了吗?

然后我就看到了这句话: 1 ≤ k i ≤ min ⁡ ( 1 0 18 , t i ) 1\le k_i\le\operatorname{min}(10^{18},t_i) 1kimin(1018,ti)。这说明一件事:我的层数不可能真的跑到 1 0 18 10^{18} 1018 那么多,在到了某个点后就必然是某个数列的第一个。那我只需要多加一个边界条件就行了。粗略算了一下,大约 60 60 60 层的时候就已经超过 1 0 18 10^{18} 1018 了。

然后就可以开始安心的写代码了,首先定义一个 dfs(x,y,f) 表示第 x x x 层的第 y y y 个是什么,而 f f f 表示以现在这个节点为根节点,我上一个要求的点是左子树的还是右子树的,为了方便,我在最初是用的 − 1 -1 1 表示我要求的点(相当于没有左子树也没有右子树的点)。

AC 代码(代码中用了大量的三目运算符压行,看不懂三目运算符的同学请先看这里):

#include<bits/stdc++.h>
#define int long long
using namespace std;
int q,t,k;
string c;
char dfs(int x,int y,int f)
{
    if(x==0)
    {
        return ((!f)?(c[y]=='A'?'B':(c[y]=='B'?'C':'A')):(c[y]=='A'?'C':(c[y]=='B'?'A':'B')));
    }
    if(y==1)
    {
        if(f==-1)
        {
            return (c[y]+x%3=='D'?'A':(c[y]+x%3=='E'?'B':c[y]+x%3));
        }
        return ((!f)?((c[y]+x%3=='D'?'A':(c[y]+x%3=='E'?'B':c[y]+x%3))=='A'?'B':((c[y]+x%3=='D'?'A':(c[y]+x%3=='E'?'B':c[y]+x%3))=='B'?'C':'A')):((c[y]+x%3=='D'?'A':(c[y]+x%3=='E'?'B':c[y]+x%3))=='A'?'C':((c[y]+x%3=='D'?'A':(c[y]+x%3=='E'?'B':c[y]+x%3))=='B'?'A':'B')));//比较抽象,可以慢慢看……
    }
    char tt=dfs(x-1,(y+1)/2,!(y&1));
    if(f==-1)
    {
        return tt;
    }
    return ((!f)?(tt=='A'?'B':(tt=='B'?'C':'A')):(tt=='A'?'C':(tt=='B'?'A':'B')));
}
signed main()
{
    cin>>c;
    c=' '+c;//把第零位变到第一位
    cin>>q;
    while(q--)
    {
        cin>>t>>k;
        if(t==0)//特判了一下
        {
            cout<<c[k]<<endl;
            continue;
        }
        cout<<dfs(t,k,-1)<<endl;//最初没有左右子树
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值