专栏文章

CF2118F Shifts and Swaps

CF2118F题解参与者 2已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@mip359rz
此快照首次捕获于
2025/12/03 05:23
3 个月前
此快照最后确认于
2025/12/03 05:23
3 个月前
查看原文
首先注意数据范围保证 1m1\sim m 均出现。
对于一操作,只需将序列看作环即可处理。对于二操作,本质上就是 aiaj1|a_i-a_j|\le 1 的数对相对位置不变。
对于 ai<ma_i < m 的位置,找到其后(环上)第一个 ai+1a_i+1 的位置 jj,然后连边 jij\to i。这样连出的外向有根树中,子树内的任何值都是不能跨出该子树的。
同时还要注意,对于一个点的所有儿子,它们的值全相等,因此也是不能交换顺序的。即这些树的儿子必须按照一定顺序排列,可以钦定 ii 的儿子是从 ii 后第一个 ai1a_i-1 的位置开始,环状排列。
如此得到序列的森林。两个序列可相同就是森林循环同构。将每棵树哈希后,使用最小表示法判断两个序列是否循环同构即可。
有根树可以确定性哈希。用一个 map <vector <int>, int> 记录,ii 子树的可用一个 vector 表示(先插入 ii,再依次插入儿子哈希值)。若该 vector 存在于 map 中,则直接调用;否则赋值新的编号。
时间复杂度 O(nlogn)\mathcal O(n\log n)
CPP
int n, m; map <vector <int>, int> mp;
vector <int> pos[MAXN], g[MAXN];
 
il auto minimum(vector <int> sec) {
    int k = 0, i = 0, j = 1, n = sec.size();
    while (k < n && i < n && j < n) {
        if (sec[(i + k) % n] == sec[(j + k) % n]) k++;
        else {
            sec[(i + k) % n] > sec[(j + k) % n] ? i = i + k + 1 : j = j + k + 1;
            if (i == j) i++;
            k = 0;
        }
    } i = min(i, j);
    rotate(sec.begin(), sec.begin() + i, sec.end());
    return sec;
}
 
il void solve() {
    read(n, m); vector <int> a, b; a.resize(n); b.resize(n);
    for (auto &v : a) read(v);
    for (auto &v : b) read(v);
    auto calc = [&](vector <int> a) {
        rep1(i, 1, m) pos[i].clear();
        rep1(i, 0, n - 1) g[i].clear(), pos[a[i]].eb(i);
        rep1(i, 0, n - 1) if (a[i] < m) {
        	auto &p = pos[a[i] + 1];
            auto it = upper_bound(begin(p), end(p), i);
            if (it == end(p)) it = begin(p);
            g[*it].eb(i);
        }
	    rep1(i, 0, n - 1) {
	        auto it = lower_bound(begin(g[i]), end(g[i]), i);
	        rotate(begin(g[i]), it, end(g[i]));
	    } vector <int> ans;
        auto dfs = [&] (auto self, int x) -> int {
            vector <int> ch; ch.eb(a[x]);
            for (auto v : g[x]) ch.eb(self(self, v));
            if (!mp.count(ch)) mp[ch] = mp.size();
            return mp[ch];
        };
        rep1(i, 0, n - 1) if (a[i] == m) ans.eb(dfs(dfs, i));
        return minimum(ans);
    }; puts(calc(a) == calc(b) ? "YES" : "NO");
}
 
int main() {
    for (int T = read(); T--; ) solve();
    return 0;
}

评论

2 条评论,欢迎与作者交流。

正在加载评论...