Loading

abc 243 d 题解

abc 243 d

AT 链接

洛谷链接

题意

有一个有着 \(2 ^ {10 ^ {100}} - 1\) 个结点的完全二叉树,每个结点编号为 \(1, 2, \dots, 2 ^ {10 ^ {100}} - 1\)\(1\) 号结点是根结点,对于 \(1 \le i < 2 ^ {10 ^ {100}} - 1\) 中的每个 \(i\),结点 \(i\) 有两个子节点:左儿子 \(2i\) 和右儿子 \(2i + 1\)

Takahashi 从顶点 \(X\) 开始执行 \(N\) 次移动,用字符串 \(S\) 表示。第 \(i\) 次移动如下:

  • 如果 \(S\) 的第 \(i\) 个字符为 U,则转到他现在所在顶点的父节点。

  • 如果 \(S\) 的第 \(i\) 个字符为 L,则转到他现在所在顶点的左孩子。

  • 如果 \(S\) 的第 \(i\) 个字符为 R,则转到他现在所在顶点的右孩子。

找到 \(N\) 次移动后 Takahashi 所在的结点编号,保证答案最多为 \(10 ^ {18}\)

思路

暴力

若当前是第 \(i\) 次操作,并且在 \(A\) 号结点上,那么:

  • 如果 $S_i = $ U\(A \rightarrow \lfloor \frac{A}{2} \rfloor\)

  • 如果 $S_i = $ L\(A \rightarrow 2 \times A\)

  • 如果 $S_i = $ R\(A \rightarrow 2 \times A + 1\)

最后输出即可。

正解

由于题目并没有保证在移动的过程中的结点编号最多为 \(10 ^ {18}\),所以,肯定不能直接模拟。

做法 1

栈。

如果先做了 LR 操作,再做了 U 操作,实际上还是在这个点上。

那么,我们只要将所有的 LR 存入栈中,每次遇到一个 U 就弹出栈顶即可。

最后,将剩下的操作全部模拟即可。

时间复杂度为 \(O(N)\)

做法 2

二进制。

先将 \(X\) 转成二进制,用一个 01 串 \(A\) 表示。

若当前是第 \(i\) 次操作,那么:

  • 如果 $S_i = $ U\(A\) 的长度减少 1。

  • 如果 $S_i = $ L,在 \(A\) 的末尾加上 \(0\)

  • 如果 $S_i = $ R,在 \(A\) 的末尾加上 \(1\)

时间复杂度为 \(O(N + \log X)\)

#include <bits/stdc++.h>

using namespace std;

const int N = 1e7 + 10;

int n, x[N], len;
string s;
int top, stk[N];

void F() {
  long long p;
  cin >> p;
  while (p) {
    x[len++] = p % 2, p /= 2;
  }
  for (int i = len - 1; i >= 0; i--) {
    stk[++top] = x[i];
  }
}

int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n;
  F(); // 转二进制
  cin >> s;
  for (int i = 0; i < s.size(); i++) {
    if (s[i] == 'U') {
      top--;
    } else if (s[i] == 'L') {
      stk[++top] = 0;
    } else {
      stk[++top] = 1;
    }
  }
  long long ans = 0;
  for (long long i = 1; top; top--, i *= 2) {
    ans += stk[top] * i; // 转回十进制
  }
  cout << ans;
  return 0;
}
posted @ 2024-09-20 17:10  chengning0909  阅读(4)  评论(0编辑  收藏  举报