大致题意:给定一个排列aaa,可以进行不限次数操作:swap(ai,ai+2)swap(a_i,a_{i+2})swap(ai,ai+2)同时swap(ai+1,ai+3)swap(a_{i+1},a_{i+3})swap(ai+1,ai+3)。问在经过任意次操作以后,字典序最小的aaa。
解:
首先,手玩一下发现,奇数位置的数永远会在奇数位置,偶数位置同理。由此我们开始考虑分开处理奇偶位置的数。
此时产生第一个错解:分别sortsortsort奇偶位置的数然后合并,不出意外的过了样例然后Wrong answer on test 2。
然后再造一些样例,发现奇偶位置的数并不是可以任意排布的。如图:
发现可以在保证奇数位置数保持不变的情况下,使得偶数位置的数发生循环换位,并非任意排布。由此产生第二个错解:用最小表示法分别处理奇偶位置的数。当然也是wa了。不过也学习了最小表示法。
然后我们继续手玩样例:分奇偶这个思路没问题,但是又发现一个样例:
在此情况下,1要往前跳三个奇数位,同时为了保持偶数位置相对次序不变,最后的2和3的次序发生了改变。原本奇数位在循环移位后应该是1 4 3 2,但是现在变成了1 4 2 3 。由此我们开始考虑计算逆序对:假如单独考虑奇数位,总共有偶数个逆序对,那么最后一定能变成完美的sortsortsort过后的次序;如果有奇数个逆序对,那么最后把最大和次大两个数的位置交换一下。偶数位置处理同理。
用线段树分别计算一下两个位置的逆序对的数量,然后考虑是否交换最后两个位置的数。然后发现样例都过不了。
对于3 4 1 2 这个样例,最小的字典序肯定是 1 2 3 4。但是按照思路,奇数位有1个逆序对,所以是3 1,偶数位也是,为4 2 。思路还是有点问题。再考虑对于操作过后的序列的最后四位ABCD。如果AC所在的位置(奇数位置或者偶数位置)逆序对数量为奇数个导致了A>C,那么考虑字典序的话,我们一定可以交换最后四个数使其变成CDAB。且CDAB一定是小于ABCD的。
由此得到正解:
首先分别处理奇数位置和偶数位置的逆序对的个数,如果有偶数个逆序对,那么最后形成的一定是sortsortsort过后的次序;如果是奇数个,那么最后面两个数要交换一下。合并以后,对于最后四个数,如果倒数第四个数大于倒数第二个数,那么我们不用考虑倒数第一个和倒数第三个数的大小关系,进行一次操作使得倒数第四个数小于倒数第二个数。
auto ans(vector<int> &a) {
vector<int> temp = a;
sort(temp.begin(), temp.end());
temp.erase(unique(temp.begin(), temp.end()), temp.end());
for (int i = 0; i < a.size(); i++) {
a[i] = lower_bound(temp.begin(), temp.end(), a[i]) - temp.begin();
}
vector<int> t(a.size() * 4);
int recnt = 0;
int mx = a.size() - 1;
function<void(int, int, int, int)> in = [&](int x, int l, int r, int val) {
if (l == r) {
t[x]++;
return;
}
int mid = (l + r) >> 1;
if (val <= mid) in(x << 1, l, mid, val);
else in(x << 1 | 1, mid + 1, r, val);
t[x] = t[x << 1] + t[x << 1 | 1];
};
function<int(int, int, int, int, int)> que = [&](int x, int l, int r, int ll, int rr) {
if (ll <= l && rr >= r) return t[x];
int mid = (l + r) >> 1;
if (ll > r || rr < l) return 0ll;
return que(x << 1, l, mid, ll, rr) + que(x << 1 | 1, mid + 1, r, ll, rr);
};
for (int i = a.size() - 1; i >= 0; i--) {
recnt += que(1, 0, mx, 0, a[i] - 1);
in(1, 0, mx, a[i]);
}
if (recnt % 2) {
swap(temp[mx], temp[mx - 1]);
return temp;
} else {
return temp;
}
}
void solve() {
int n;
cin >> n;
vector<vector<int>> a(2);
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
a[i % 2].push_back(x);
}
auto odd = ans(a[1]);
auto even = ans(a[0]);
int oi = 0, ei = 0;
if (n % 2) {
if (even[even.size() - 2] > even[even.size() - 1]) {
swap(even[even.size() - 2], even[even.size() - 1]);
swap(odd[odd.size() - 2], odd[odd.size() - 1]);
}
} else {
if (odd[odd.size() - 2] > odd[odd.size() - 1]) {
swap(odd[odd.size() - 2], odd[odd.size() - 1]);
swap(even[even.size() - 2], even[even.size() - 1]);
}
}
for (int i = 1; i <= n; i++) {
if (i % 2) cout << odd[oi++] << " ";
else cout << even[ei++] << " ";
}
cout << endl;
}