题目链接
ps:看了题解
先考虑
a
a
a是全排练的情况:
设
p
o
s
[
v
]
pos[v]
pos[v]为
v
v
v在
a
a
a数组中出现的位置即:
p
o
s
[
a
[
i
]
]
=
i
pos[a[i]]=i
pos[a[i]]=i
为了满足题意条件,首先要把
n
n
n放在最后一个位置,并且将
n
n
n放在最后一个位置,还要满足:
- b [ n ] = n b[n]=n b[n]=n
- 1 < = i , j < n 1<=i,j<n 1<=i,j<n, a [ i ] a[i] a[i]与 a [ j ] a[j] a[j]的大小关系与 b [ i ] b[i] b[i], b [ j ] b[j] b[j]之间的大小关系相同
从而达到与原序列相比序列长度减一的同解子问题
若要满足这个情况,则要交换
(
p
o
s
[
a
[
n
]
+
1
]
,
n
)
(pos[a[n]+1],n)
(pos[a[n]+1],n),
(
p
o
s
[
a
[
n
]
+
2
]
,
n
)
.
.
.
(pos[a[n]+2],n)...
(pos[a[n]+2],n)...,
(
p
o
s
[
n
]
,
n
)
(pos[n],n)
(pos[n],n)
经过交换以后,容易发现,最后一个位置即为
n
n
n,而交换之后序列的相对大小并没有改变,只是相当于原序列每个位置减一(除位置n外)
例如:
3 2 1
swap(pos[2], 3)
3 1 2
swap(pos[3], 3)
2 1 3
若不是全排列:
那就以数值为第一关键字,位置为第二关键字,重新赋值组成全排列,与原序列同解,因为逆序对的个数并没有改变
例如:
3 3 2
逆序对:(1, 3), (2, 3)
2 3 1
逆序对:(1, 3), (2, 3)
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <set>
#include <vector>
#include <cassert>
using namespace std;
typedef pair<int, int> pi;
const int maxn = 1010;
int n, cnt, T;
int a[maxn], p[maxn], pos[maxn], a_val[maxn];
vector <pi> ans;
void work(int p1, int p2) {
pos[a[p1]] = p2, pos[a[p2]] = p1;//要改变pos的值
swap(a[p1], a[p2]);
ans.push_back(pi(p1, p2));
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a_val[++cnt] = a[i];
}
sort(a_val + 1, a_val + cnt + 1);
cnt = unique(a_val + 1, a_val + cnt + 1) - (a_val + 1);
//cnt此处记录不同的个数有多少个,并删除序列中所有相邻的重复元素(只剩一个)
int x = 0;
for (int i = 1; i <= cnt; i++)
for (int j = 1; j <= n; j++)
if (a[j] == a_val[i])
p[j] = ++x;
for (int i = 1; i <= n; i++) a[i] = p[i];
for (int i = 1; i <= n; i++) pos[a[i]] = i;
for (int i = n; i >= 1; i--)
for (int j = a[i] + 1; j <= i; j++)
work(pos[j], i);
cout << ans.size() << endl;
for (int i = 0; i < ans.size(); i++) cout << ans[i].first << " " << ans[i].second << endl;
return 0;
}