1 条题解
-
0
不是纯模拟题,怎么会呢?
当没有
TRIGGER和TOGGLETRIGGERREPLACE指令时,这道题就是一道很容易的模拟题。我们记 为 号机器人的「指令」的编号,初始时,令 。
接着,按顺序处理每一条「指令」的输出信息。根据输出信息,我们得知该「指令」的编号为 ,并据此完善该「指令」的类型、左手/右手等信息。然后,如果该「指令」是
SWAP,我们交换 和 ;如果是MOVE,也进行相应的修改。最后,按顺序输出初始时 号机器人的「指令」(即编号为 的「指令」)的详细信息。若仍有不确定的信息,说明该信息是无关紧要的,随意输出一个合理值即可。
而
TRIGGER和TOGGLETRIGGERREPLACE指令使问题复杂起来。首先,
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 模型并求解,根据结果输出即可。总的流程是:
- 遍历并处理每一条「指令」的输出信息。
- 完善该「指令」的信息。
- 根据该「指令」和上一条「指令」之间的关系,维护「选择集合」。
- 实现该「指令」本身执行时的效果。
- 注意处理最后一条「指令」对「选择集合」的影响。
- 根据有关限制建立 2-SAT 模型。
TOGGLETRIGGERREPLACE指令的限制可以直接在遍历时处理。
- 求解 2-SAT。
- 输出结果。
- 注意某些无关紧要的信息,如
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
- 上传者