题解 CF1375E Inversion SwapSort(构造)

题目链接
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;
}

参考博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值