首页 > 代码库 > uva 1611:Crane(构造 Grade D)

uva 1611:Crane(构造 Grade D)

题目链接

题意:

一个序列,你可以选择其中偶数长度的一段,然后中间切开,左右两段交换。现给你一个1~n的某个排列,求一个交换方案,使得排列最终有序。(交换次数 < 9^6)

思路:

从左到右,依次把一个个数放到位。把一个数放到正确的位置,观察发现最多两步。第i个数,若现在的位置在 [i+1, (n+i)/2] 内,则可以一次到位。若在它右边,则可以通过一次,使得其到这个范围内。

代码:

#include <cstdio>#include <cstring>#include <cstdlib>#include <cassert>#include <algorithm>using namespace std;#define N 10100int a[N];int id[N];int n;struct Ans{    int l, r;    Ans(int _l=0, int _r =0) : l(_l), r(_r){}}ans[2*N];int ap;void myswap(int l, int r) {    ans[ap++] = Ans(l,r);    //printf("l = %d, r = %d\n", l, r);    assert((r-l+1)%2 == 0);    int mid = (l+r)/2;    int lp = l;    int rp = mid+1;    while (lp <= mid) {        swap(id[a[lp]], id[a[rp]]);        swap(a[lp], a[rp]);        lp++; rp++;    }    //puts("after---");    //for (int i = 0; i < n; i++) {    //    printf("%d ", a[i]+1);    //}puts("");}int main() {    int t;    scanf("%d", &t);    while (t--) {        scanf("%d", &n);        for (int i = 0; i < n; i++) {            scanf("%d", &a[i]);            a[i]--;        }        for (int i = 0; i < n; i++) {            id[a[i]] = i;        }        ap = 0;        for (int i = 0; i < n; i++) {            if (id[i] == i) continue;            int flag = (n+i)/2;            if (id[i] > flag) {                myswap( flag - (id[i]-flag-1) ,id[i] );            }            //printf("i = %d,  swap(%d->%d)\n", i, i, id[i]+(id[i]-i-1));            myswap(i, id[i] + (id[i]-i-1));        }        //for (int i = 0; i < n; i++) {        //    printf("%d ", a[i]);        //}puts("");        printf("%d\n", ap);        for (int i = 0; i < ap; i++) {            printf("%d %d\n", ans[i].l+1, ans[i].r+1);        }    }    return 0;}

 

uva 1611:Crane(构造 Grade D)