Quartet Swapping

什么你说你智商不够注意不到特殊性质?其实这是道模拟题。我要让所有人都知道惊为天人的模拟做法!

由于要求字典序最小,贪心地做肯定是对的。奇数位的数只能移动到奇数位,偶数位的数只能移动到偶数位(这个总能注意到吧),因此对于每个数我们可以从所有奇数位 / 偶数位中挑一个最小的,然后尝试交换过来。

一但确定好要选择哪个数,就可以把在原数组上模拟,把目标数换过来。我们把相邻的两个看成一组,那这个交换过程就类似于冒泡排序,一定可以做到其他元素位置不变,只交换所需要的四个,所以可以一步到位直接换过来。而如果目标数字在最后一个不能分组,则可以先交换最后四个,把他换到前面来。

主播主播,那怎么快速找到那个最小的数是在哪里,并且可以动态维护他的位置呢?答案是使用 map。我用了两个 multimap,一个存奇下标,一个存偶下标,键为数字,值为数字所对应的位置,同时还用一个 vector 存下其对应的迭代器以支持随机访问。操作时同时交换 multimap 中的下标和 vector 中的迭代器,已经确定好位置的数直接从 multimap 中删掉就好了。

#include <cstddef>
#include <iostream>
#include <map>
#include <utility>
#include <vector>
using namespace std;
istream& fin = cin;
ostream& fout = cout;
using ui = unsigned int;
using uli = unsigned long long int;
using li = long long int;
int main(void) {
  ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
  size_t T;
  fin >> T;
  while (T--) {
    size_t n;
    fin >> n;
    using It = multimap<ui, size_t>::iterator;
    multimap<ui, size_t> pa, pb;
    vector<It> a(n);
    for (size_t i = 0; i < n; ++i) {
      ui x;
      fin >> x;
      a[i] = (i % 2 == 0 ? pa : pb).emplace(--x, i);
    }
    auto operate = [&](It ta, It tb) {
      swap(a[ta->second], a[tb->second]);
      swap(ta->second, tb->second);
    };
    vector<ui> ans;
    for (size_t i = 0; i < n - 3; ++i) {
      auto pt = (i % 2 == 0 ? pa : pb).begin();
      if (pt->second == n - 1)
        operate(a[n - 4], a[n - 2]), operate(a[n - 3], a[n - 1]);
      if (pt->second != i)
        operate(a[i + 1], a[pt->second + 1]), operate(a[i], pt);
      ans.emplace_back(pt->first);
      (i % 2 == 0 ? pa : pb).erase(pt);
    }
    for (size_t i = n - 3; i < n; ++i) ans.emplace_back(a[i]->first);
    for (auto i : ans) fout << i + 1 << ' ';
    fout << '\n';
  }
  return 0;
}
posted @ 2025-05-15 15:40  MrPython  阅读(11)  评论(0)    收藏  举报  来源