#Trie#AGC044 C - Strange Dance

题意

\(3^n\) 个人在绕圈圈跳舞。我们从任意一个人开始,给这些人环绕标号,记为 \(0,1,\dots,3^n-1\)

现在有两种舞 :

  • Salasa 舞。所有人走向其对应的位置,位于位置 \(i\) 的人走向第 \(j\) 个位置当且仅当 \(i,j\) 的三进制表示,\(1\) 对应 \(2\)\(2\) 对应 \(1\)。比如,\((46)_{10}=(1201)_3\) 可以走向 \((65)_{10}=(2102)_3\),当然 \(65\) 也走向 \(46\)
  • Rumba 舞。所有人走向其所在位置编号加 \(1\) 的位置。如果等于 \(3^n−1\),去 \(0\)

现在给你一个 \(T\) 序列表示以上两种舞。请问最后每个人站在哪里?


分析

从低位到高位建 \(Trie\),维护 \(w[p]\) 表示位置为根结点到结点 \(p\) 的路径所表示的三进制数的是第几个人。

处理 \(S\) 也就是实现交换 \(trie[p][1]\)\(trie[p][2]\),需要实现懒标记进行延迟交换。

处理 \(T\) 也就是全局加一,三进制就是让 \(trie[p][(z+1)\bmod 3]=trie[p][z]\)

时间复杂度 \(O(3^n+n|T|)\)


代码

#include <iostream>
#include <string>
using namespace std;
const int N = 800011;
string T;
int rt, n, len, tot, three[21], trie[N][3], w[N], lazy[N], ans[N];
void build(int &rt, int dep, int now) {// 建 Trie
    if (!rt)
        rt = ++tot;
    if (dep == n) {
        w[rt] = now;
        return;
    }
    for (int i = 0; i < 3; ++i)
        build(trie[rt][i], dep + 1, now + i * three[dep]);
}
void plusone(int rt) {// 全局加一
    if (!trie[rt][0])
        return;
    if (lazy[rt]) {// 延迟标记
        for (int i = 0; i < 3; ++i)
            lazy[trie[rt][i]] ^= 1;
        swap(trie[rt][1], trie[rt][2]);
        lazy[rt] = 0;
    }
    int t = trie[rt][0];
    trie[rt][0] = trie[rt][2];
    trie[rt][2] = trie[rt][1];
    trie[rt][1] = t;
    plusone(trie[rt][0]);
}
void dfs(int rt, int dep, int now) {
    if (dep == n) {
        ans[w[rt]] = now;
        return;
    }
    if (lazy[rt]) {
        for (int i = 0; i < 3; ++i)
            lazy[trie[rt][i]] ^= 1;
        swap(trie[rt][1], trie[rt][2]);
        lazy[rt] = 0;
    }
    for (int i = 0; i < 3; ++i)
        dfs(trie[rt][i], dep + 1, now + i * three[dep]);
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n >> T, len = T.length();
    three[0] = 1;
    for (int i = 1; i <= n; ++i)
        three[i] = three[i - 1] * 3;
    build(rt, 0, 0);
    for (int i = 0; i < len; ++i)
        if (T[i] == 'S')
            lazy[rt] ^= 1;
        else
            plusone(rt);
    dfs(rt, 0, 0);
    for (int i = 0; i < three[n]; ++i)
        cout << ans[i] << ' ';
    return 0;
}
posted @ 2025-02-09 11:28  lemondinosaur  阅读(13)  评论(0)    收藏  举报