给定一个长度为 的排列 ,同时你有一个长度为 的排列 ,设 。你需要重新排列 的元素,满足依次交换 和 后有 。
。
首先有一个结论,交换 和 ()后一定会改变 的逆序对个数的奇偶性,证明:
- 和 的 参与构成的逆序对显然没有影响;
- 的 :
设有 个 满足 且 ,有 个 满足 且 ;
有 个 满足 且 ,有 个 满足 且 ;
那么交换之前 中的逆序对个数显然是 ,交换之后是 ,由于 所以 和 奇偶性一样,而 ,所以逆序对个数的奇偶性一定会被改变。
那么 的逆序对个数的奇偶性和 的奇偶性不一样则无解,接下来考虑通过构造来证明其他情况一定有解。
考虑先把所有 的 通过不断交换满足 的 和 ,最后再交换满足 的 和 ,这样就可以消掉 ,把问题转化为大小为 的子问题。
那么现在问题就变成了要让进行完所有交换之后 。
不难发现,由于逆序对个数()和 的奇偶性相同,那么此时的 一定满足 ,所以考虑不断消掉四个位置来把问题转化为 的子问题。
考虑这样的过程,其中 是剩下的位置(不包含 和 ):
inline void slove(int x,int y)
{
auto p=st.begin();
while(p!=st.end()) swp(x,*p++);
swp(x,y);
p=st.end();
while(p!=st.begin()) swp(y,*--p);
}
不难发现这样就可以把 和 消掉且交换 和 ,那么考虑四个位置 ,可以这样把它们消掉:
st.erase(x);
st.erase(y);
st.erase(z);
st.erase(w);
slove(x,y);
slove(z,w);
swp(x,z),swp(y,w);
swp(x,w),swp(y,z);
那么不断执行以上操作,直到 即可。
时间复杂度 。
代码如下:
#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
const int S=1005;
struct node
{
int x,y;
}ans[S*S];
int n,a[S],b[S];
int tr[S];
int tot;
set<int> st;
inline void add(int pos,int x)
{
for(int i=pos;i<=n;i+=i&-i) tr[i]+=x;
}
inline int que(int pos)
{
int res=0;
for(int i=pos;i>=1;i-=i&-i) res+=tr[i];
return res;
}
inline void swp(int x,int y)
{
swap(b[x],b[y]);
ans[++tot]=(node){min(x,y),max(x,y)};
}
inline void slove(int x,int y)
{
auto p=st.begin();
while(p!=st.end()) swp(x,*p++);
swp(x,y);
p=st.end();
while(p!=st.begin()) swp(y,*--p);
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=i;
int tmp=n*(n-1)/2&1;
for(int i=n;i>=1;i--) tmp^=que(a[i])&1,add(a[i],1);
if(tmp!=0) return puts("NO"),0;
else puts("YES");
for(int i=1;i<=n;i++) st.insert(i);
while(1)
{
int pos=-1;
for(int i=1;i<=n;i++) if(b[i]!=a[i]) pos=i;
if(pos==-1) break;
for(int i=1;i<=n;i++) if(i!=pos&&b[i]!=a[pos]&&st.count(i)) swp(pos,i);
for(int i=1;i<=n;i++)
{
if(b[i]==a[pos])
{
swp(pos,i);
break;
}
}
st.erase(pos);
}
while(st.size()>=4)
{
int x=*st.begin();st.erase(x);
int y=*st.begin();st.erase(y);
int z=*st.begin();st.erase(z);
int w=*st.begin();st.erase(w);
slove(x,y);
slove(z,w);
swp(x,z),swp(y,w);
swp(x,w),swp(y,z);
}
for(int i=1;i<=tot;i++) printf("%d %d\n",ans[i].x,ans[i].y);
return 0;
}