题意
给你一个排列,每次可以选择偶数长度的区间,交换这个区间的左右两半的数,问你操作数将其从小到大排序
思路
类似于选择排序,我们每次将一个数归位,这样我们只需要考虑对于当前的 j 在 j 右边的所有数就可以了,对于 j ,pos[j]表示现在 j 这个数的位置,我们考虑pos[j]-1-j+1,n-j+1两者的长度,如果后者长度小于前者,这样我们交换一次就能是的 j 归位置,否则如果后者的长度大,那说明交换一次是不满足条件的,因为这样的区间超过了n,所以我们把pos[j]以小的长度这个区间往前交换,这样第二次的交换就跟之前的一样了。所以最多是2n次交换就能满足
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN=10000+10;
typedef pair<int,int> pii;
int pos[MAXN],num[MAXN];
int n;
vector<pii> vt;
void SWAP(int l,int r)
{
int minn=min(r-l,n-r+1);
int l1=r-minn,r1=r+minn-1;
vt.push_back(pii(l1,r1));
for(int i=0;l1+i<r;i++)
{
swap(num[l1+i],num[r+i]);
swap(pos[num[l1+i]],pos[num[r+i]]);
}
}
int main()
{
int T;cin>>T;
while(T--)
{
vt.clear();
cin>>n;
for(int i=1;i<=n;i++) cin>>num[i],pos[num[i]]=i;
for(int j=1;j<=n;j++)
{
while(pos[j]!=j)
{
SWAP(j,pos[j]);
}
}
printf("%d\n",vt.size());
for(int i=0;i<vt.size();i++)
{
printf("%d %d\n",vt[i].first,vt[i].second);
}
}
return 0;
}