其实这道题还是挺简单的。
怎么说呢,看到这道题的后我瞬间就想到了分治和二叉树(主要是因为一个字母可以分成两个字母),于是我就写了个 dfs,但有个问题:题目给的数据范围是 0 ≤ t i ≤ 1 0 18 0\le t_i\le10^{18} 0≤ti≤1018,而写二叉树则是一层一层往上跑,这不就成了 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) 1≤ki≤min(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;
}