题解
将所有逆序对((x_i,y_i))按照(y_i)降序排序,若(y_i)相等则按(a_{x_i})((a)为原序列)升序排序,若两者均相等则按(x_i)升序排序即可。
对于序列(a),如果每次寻找一组逆序对并将它们交换,易得经过若干组操作后一定可以化为单调不降的序列,因此我们只需保证在交换原有逆序对过程中不产生新逆序对即可。考虑从后往前依次归位((y_i)降序),易得按(a_{x_i})升序排序的话,原先最小的(a_{x_i})到了次小的(a_{x_i})位置上,次小的则到了第三小的位置上,以此类推,而最大的到达了(y_i)上,(a_{y_i})到达了最小的(a_{x_i})的位置上。这样可以使([1,y_i])间最大的元素位于(y_i),完成归位,而其余的(a_{x_i})所在位置的元素则分别变小了一等。考虑其中一个(a_{x_i}),([1,x_i))间大于(a_{x_i})的元素交换后仍大于(a_{x_i}),逆序对不变。而((x_i,n])间小于(a_{x_i})的元素一定仍小于(a_{x_i}),因为交换后每一位(除去(a_{y_i})不考虑)只是变小并未变大。不过,当(a_{x_i})中元素出现重复时,需要保证交换后最小的元素位于最前,也就是按(x_i)升序排序。
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
struct node {int x,y;} inv[N*N];
int a[N],n,cnt;
bool cmp(node x,node y) {return x.y>y.y || (x.y==y.y && a[x.x]<a[y.x]) || (x.y==y.y && a[x.x]==a[y.x] && x.x<y.x);}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(a[j]<a[i]) inv[++cnt].x=i,inv[cnt].y=j;
sort(inv+1,inv+cnt+1,cmp);
for(int i=1;i<=cnt;i++) swap(a[inv[i].x],a[inv[i].y]);
bool flag=0;
for(int i=1;i<=n;i++)
if(a[i]<a[i-1] && i>1) {flag=1; break;}
if(flag) {printf("-1"); return 0;}
printf("%d
",cnt);
for(int i=1;i<=cnt;i++) printf("%d %d
",inv[i].x,inv[i].y);
return 0;
}