题目链接:http://codeforces.com/contest/1148/problem/C
题目大意:
给你一个置换,(1, n)没有重复元素的排列。
让你输出交换a[i], a[j]使得置换有序(从小到大),必须满足(abs(i-j)>=n/2),
可以证明:最多5*n次交换。
思路:就是暴力,map存每个元素的位置。
循环遍历:1-n
假如遍历到i。这本来的元素应该是i。用map查找i的位置p。
如果abs(p-i)>=n/2,直接交换。
如果abs(p-i)<=n/2。说明他们不能直接交换,需要中间元素。
p和i一定能和1或者n进行交换。 所以就是选择他们都可以交换的元素作为中间元素。
注意交换后要把中间元素还原。每次把一个位置是的元素交换到正确的位置最多交换4次,所以最多5*n次交换成立。
交换数组开5*n+10
我数组开小了,一直WA11,为什么不是RE???,看了看是没有满足abs(p-i)>=n/2,
但是我的代码逻辑是绝对不可能出现这种错误的。
后来发现是数组越界了。地址访问到之前保存的操作,并且修改之前的结果。才造成这种错误。
总之:出现奇怪的错误,就看看是不是数组越界了。
#include<bits/stdc++.h>
#define LL long long
//#define p1 first
//#define p2 second
using namespace std;
//memset(a, 0, sizeof(a));
//stack堆栈 queue队列 priority_queue优先队列
//vector向量 multiset平衡二叉树 deque双端队列
//pair{T1 first;T2 second;} greater<T>
//unordered_map 哈希map
//binary_search();//二分查找。返回下标,没有返回-1
//for(auto &i:s)
//{
// cout<<i<<endl;
//}
map<int, int> mp;
int a[300010];
int x[1000010], y[1000010], cut=0;
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
mp[a[i]]=i;
}
for(int i=1;i<=n;i++)
{
if(a[i]==i)
{
continue;
}
int p=mp[i];
if(abs(p-i)<(n/2))
{
int L, R;
if(i-1>=n/2){
L=1;
}else{
L=n;
}
if(p-1>=n/2){
R=1;
}else{
R=n;
}
if(L==R)
{
x[cut]=p;
y[cut]=L;
cut++;
x[cut]=L;
y[cut]=i;
cut++;
x[cut]=L;
y[cut]=p;
cut++;
mp[i]=i;
mp[a[i]]=p;
swap(a[i], a[p]);
}
else
{
x[cut]=R;
y[cut]=p;
cut++;
x[cut]=R;
y[cut]=L;
cut++;
x[cut]=L;
y[cut]=i;
cut++;
x[cut]=p;
y[cut]=R;
cut++;
mp[i]=i;
mp[a[i]]=L;
mp[a[L]]=p;
swap(a[R], a[p]);
swap(a[R], a[L]);
swap(a[i], a[L]);
swap(a[R], a[p]);
}
}
else
{
x[cut]=p;
y[cut]=i;
mp[a[i]]=p;
mp[i]=i;
swap(a[p], a[i]);
cut++;
}
}
printf("%d\n",cut);
for(int i=0;i<cut;i++)
{
printf("%d %d\n",x[i], y[i]);
}
return 0;
}