CF1375E Solution

题目链接

题解

将所有逆序对\((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\n",cnt);
	for(int i=1;i<=cnt;i++) printf("%d %d\n",inv[i].x,inv[i].y);
	return 0;
}
posted @ 2021-08-12 11:13  violet_holmes  阅读(28)  评论(0编辑  收藏  举报