1 条题解

  • 0
    @ 2026-5-13 8:15:45

    不是纯模拟题,怎么会呢?

    当没有 TRIGGERTOGGLETRIGGERREPLACE 指令时,这道题就是一道很容易的模拟题。

    我们记 fif_iii 号机器人的「指令」的编号,初始时,令 fi=if_i=i

    接着,按顺序处理每一条「指令」的输出信息。根据输出信息,我们得知该「指令」的编号为 fidf_{\text{id}},并据此完善该「指令」的类型、左手/右手等信息。然后,如果该「指令」是 SWAP,我们交换 fid2f_{\text{id2}}fid3f_{\text{id3}};如果是 MOVE,也进行相应的修改。

    最后,按顺序输出初始时 ii 号机器人的「指令」(即编号为 ii 的「指令」)的详细信息。若仍有不确定的信息,说明该信息是无关紧要的,随意输出一个合理值即可。

    TRIGGERTOGGLETRIGGERREPLACE 指令使问题复杂起来。

    首先,TOGGLETRIGGERREPLACE 指令产生的两条新「指令」,我们用和其他「指令」不同的编号表示它们。被 TOGGLETRIGGERREPLACE 指令「切换」的「指令」前后大部分信息相同而编号不同,这些信息可以记录在同一个地方,以避免两条「指令」的信息的不同步。

    对于 TRIGGER,容易知道,TRIGGER 指令的触发和非 TRIGGER 指令的执行可能产生相同的输出信息,因此输出信息为 <COMMANDNAME> 的「指令」有 TRIGGER <ANOTHERCOMMANDNAME>: <COMMANDNAME><COMMANDNAME> 两种可能的形式。

    具体地,我们发现:

    • 只有「当一个其他机器人『执行』完一条『指令』之后,且『右手』指向自己的时候」,自己的 TRIGGER 指令才可能被触发。
      • 从而,一条「指令」最多触发一条 TRIGGER 指令。
        • TRIGGER <COMMANDNAME(非 TRIGGER)> 指令的上一条执行的「指令」一定是 <COMMANDNAME>TRIGGER <ANOTHERCOMMANDNAME>: <COMMANDNAME> 指令。
        • 输出信息为 <COMMANDNAME> 的「指令」的下一条执行的「指令」如果是 TRIGGER,则下一条「指令」要么是 TRIGGER <COMMANDNAME>,要么是 TRIGGER TRIGGER
        • 一个机器人「执行」完一条输出信息为 <COMMANDNAME> 的「指令」之后,若这是最后一条「指令」或「右手」不指向下一条「指令」的执行者,
          • 若这不是最后一条「指令」,则下一条「指令」一定不是 TRIGGER 指令;
          • 若「右手」不指向它自己,则其「右手」指向的机器人的「指令」一定不是 TRIGGER <COMMANDNAME> 指令。

    对于每条「指令」,我们根据上述结论维护「若这条『指令』是 TRIGGER <COMMANDNAME><COMMANDNAME> 可能的选择集合」。

    假如一条「指令」是 TRIGGER,而且根据上述「选择集合」,它既可能是 TRIGGER <COMMANDNAME(非 TRIGGER)>,又可能是 TRIGGER TRIGGER,那么这条「指令」一定可以是前者,不必额外考虑后者的情况。

    假如一条「指令」是 TRIGGER,但是根据上述「选择集合」,它只可能是 TRIGGER TRIGGER,由于在处理输出信息的过程中,我们并不知道每条「指令」是否一定是 TRIGGER,从而不能确定触发这条「指令」的「指令」是否都是 TRIGGER,因此我们需要再进行一遍处理:

    • TRIGGER TRIGGER 指令的上一条执行的「指令」一定是 TRIGGER 指令。
      • TRIGGER 指令的下一条执行的「指令」一定不是 TRIGGER TRIGGER 指令。
    • 一个机器人「执行」完 TRIGGER 指令之后,若这是最后一条「指令」或「右手」不指向下一条「指令」的执行者,且「右手」不指向它自己,则其「右手」指向的机器人的「指令」不是 TRIGGER TRIGGER 指令。

    因为这样的「指令」如果是 TRIGGER,则一定是 TRIGGER TRIGGER,所以可以直接据此判断其是否可以是 TRIGGER

    我们再配合另外的限制:

    • 若对一条「指令」维护的「选择集合」是空集,则这条「指令」不是 TRIGGER 指令。
    • TOGGLETRIGGERREPLACE 指令「切换」的「指令」前后有且仅有一个是 TRIGGER 指令。

    对于每条「指令」是否是 TRIGGER 指令,我们根据上述有关限制建立 2-SAT 模型并求解,根据结果输出即可。

    总的流程是:

    1. 遍历并处理每一条「指令」的输出信息。
      1. 完善该「指令」的信息。
      2. 根据该「指令」和上一条「指令」之间的关系,维护「选择集合」。
      3. 实现该「指令」本身执行时的效果。
    2. 注意处理最后一条「指令」对「选择集合」的影响。
    3. 根据有关限制建立 2-SAT 模型。
      • TOGGLETRIGGERREPLACE 指令的限制可以直接在遍历时处理。
    4. 求解 2-SAT。
    5. 输出结果。
      • 注意某些无关紧要的信息,如 TOGGLETRIGGERREPLACE h <COMMANDNAME> <NEWCOMMAND>TRIGGER 指令「切换」时 <COMMANDNAME> 的内容,任意「指令」名称都是可以的。
    #include <bits/stdc++.h>
    int main() {
    #ifdef ONLINE_JUDGE
        std::ios::sync_with_stdio(false);
        std::cin.tie(nullptr);
        std::cout.tie(nullptr);
    #endif
        int n, k;
        std::cin >> n >> k;
        std::vector<std::pair<int, int>> h(n);
        for (int i = 0; i < n; ++i)
            std::cin >> h[i].first >> h[i].second;
        typedef std::uint8_t command_name;
        static const command_name none = 0, slackoff = 1, move = 2, swap = 4, toggletriggerreplace = 8, trigger = 16;
        struct command {
            command_name name = slackoff | move | swap | toggletriggerreplace, tname = slackoff | move | swap | toggletriggerreplace | trigger;
            int a, b, c;
        };
        std::vector<int> f(n);
        std::iota(f.begin(), f.end(), 0);
        std::vector<command> c(n);
        std::vector<int> p(n, -1);
        std::vector<std::vector<int>> adj(n * 2), jda(n), jdb(n);
        int cnt = n;
        int lar = -1, lax = -1;
        command_name la = none;
        for (int i = 0; i < k; ++i) {
            std::string s;
            std::cin >> s;
            if (s == "SLACKOFF") {
                int x;
                std::cin >> x;
                c[f[x]].name = slackoff;
                if (lar == x)
                    c[f[x]].tname &= la | trigger, jda[f[x]].push_back(lax);
                else {
                    c[f[x]].tname &= none;
                    if (~lar)
                        c[f[lar]].tname &= ~la, jdb[f[lar]].push_back(lax);
                }
                lax = f[x];
                la = slackoff;
                lar = h[x].second == x ? -1 : h[x].second;
            } else if (s == "MOVE") {
                int x, y, z;
                std::cin >> x >> y >> z;
                c[f[x]].name = move;
                c[f[x]].a = y;
                c[f[x]].b = (z - (y == 0 ? h[x].first : h[x].second) + n) % n;
                if (lar == x)
                    c[f[x]].tname &= la | trigger, jda[f[x]].push_back(lax);
                else {
                    c[f[x]].tname &= none;
                    if (~lar)
                        c[f[lar]].tname &= ~la, jdb[f[lar]].push_back(lax);
                }
                lax = f[x];
                (y == 0 ? h[x].first : h[x].second) = z;
                la = move;
                lar = h[x].second == x ? -1 : h[x].second;
            } else if (s == "SWAP") {
                int x, y, z;
                std::cin >> x >> y >> z;
                c[f[x]].name = swap;
                if (lar == x)
                    c[f[x]].tname &= la | trigger, jda[f[x]].push_back(lax);
                else {
                    c[f[x]].tname &= none;
                    if (~lar)
                        c[f[lar]].tname &= ~la, jdb[f[lar]].push_back(lax);
                }
                lax = f[x];
                std::swap(f[y], f[z]);
                la = swap;
                lar = h[x].second == x ? -1 : h[x].second;
            } else if (s == "TOGGLETRIGGERREPLACE") {
                int x, y;
                std::cin >> x >> y;
                c[f[x]].name = toggletriggerreplace;
                if (h[x].first == y && h[x].second != y)
                    c[f[x]].a = 0;
                else if (h[x].first != y && h[x].second == y)
                    c[f[x]].a = 1;
                c[f[x]].b = cnt, c[f[x]].c = cnt + 1;
                if (lar == x)
                    c[f[x]].tname &= la | trigger, jda[f[x]].push_back(lax);
                else {
                    c[f[x]].tname &= none;
                    if (~lar)
                        c[f[lar]].tname &= ~la, jdb[f[lar]].push_back(lax);
                }
                lax = f[x];
                adj.emplace_back(), adj.emplace_back(), jda.emplace_back(), jdb.emplace_back(), c.emplace_back(), p.push_back(-1);
                adj[f[y] << 1].push_back(cnt << 1 | 1), adj[cnt << 1 | 1].push_back(f[y] << 1);
                adj[f[y] << 1 | 1].push_back(cnt << 1), adj[cnt << 1].push_back(f[y] << 1 | 1);
                p[cnt] = f[y];
                c[cnt] = c[f[y]];
                c[cnt].tname = slackoff | move | swap | toggletriggerreplace | trigger;
                f[y] = cnt++;
                adj.emplace_back(), adj.emplace_back(), jda.emplace_back(), jdb.emplace_back(), c.emplace_back(), p.push_back(-1);
                f[x] = cnt++;
                la = toggletriggerreplace;
                lar = h[x].second == x ? -1 : h[x].second;
            }
        }
        if (~lar)
            c[f[lar]].tname &= ~la, jdb[f[lar]].push_back(lax);
        for (int i = cnt - 1; i >= 0; --i)
            if (~p[i])
                c[p[i]].name &= c[i].name, c[p[i]].a = c[i].a, c[p[i]].b = c[i].b, c[p[i]].c = c[i].c;
        for (int i = 0; i < cnt; ++i)
            if (c[i].tname == none)
                adj[i << 1 | 1].push_back(i << 1);
        for (int i = 0; i < cnt; ++i) {
            if (c[i].tname == trigger) {
                for (int j : jda[i])
                    adj[j << 1].push_back(i << 1), adj[i << 1 | 1].push_back(j << 1 | 1);
                for (int j : jdb[i])
                    adj[j << 1 | 1].push_back(i << 1), adj[i << 1 | 1].push_back(j << 1);
            }
        }
        std::vector<int> dfn(cnt * 2, -1), low(cnt * 2, -1), scc(cnt * 2, -1);
        std::vector<bool> ins(cnt * 2);
        std::stack<int> s;
        int doc = 0, scccnt = 0;
        std::function<void(int)> dfs = [&](int x) -> void {
            dfn[x] = low[x] = doc++;
            s.push(x);
            ins[x] = true;
            for (int i : adj[x]) {
                if (!~dfn[i]) {
                    dfs(i);
                    low[x] = std::min(low[i], low[x]);
                } else if (ins[i]) {
                    low[x] = std::min(dfn[i], low[x]);
                }
            }
            if (low[x] >= dfn[x]) {
                int t;
                do {
                    t = s.top();
                    scc[t] = scccnt;
                    ins[t] = false;
                    s.pop();
                } while (t != x);
                ++scccnt;
            }
            return;
        };
        for (int i = 0; i < cnt * 2; ++i)
            if (!~dfn[i])
                dfs(i);
        for (int i = 0; i < cnt; ++i)
            assert(scc[i << 1] != scc[i << 1 | 1]);
        auto get_command_name = [&](command_name name) -> std::string {
            if (name & slackoff)
                return "SLACKOFF";
            if (name & move)
                return "MOVE";
            if (name & swap)
                return "SWAP";
            if (name & toggletriggerreplace)
                return "TOGGLETRIGGERREPLACE";
            if (name & trigger)
                return "TRIGGER";
            return "";
        };
        std::function<void(command, bool)> write_command = [&](command x, bool triggered) -> void {
            if (triggered)
                std::cout << "TRIGGER " << get_command_name(x.tname) << ": ";
            if (x.name & slackoff) {
                std::cout << "SLACKOFF";
                return;
            }
            if (x.name & move) {
                std::cout << "MOVE " << x.a << " " << x.b;
                return;
            }
            if (x.name & swap) {
                std::cout << "SWAP";
                return;
            }
            if (x.name & toggletriggerreplace) {
                std::cout << "TOGGLETRIGGERREPLACE " << x.a << " " << (c[x.b].tname == none ? get_command_name(slackoff) : get_command_name(c[x.b].tname)) << " ";
                return write_command(c[x.c], scc[x.c << 1] > scc[x.c << 1 | 1]);
            }
            return;
        };
        for (int i = 0; i < n; ++i)
            write_command(c[i], scc[i << 1] > scc[i << 1 | 1]), std::cout << '\n';
        return 0;
    }
    
    • 1

    信息

    ID
    7429
    时间
    2000ms
    内存
    1024MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者