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 10100

int 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;
}
时间: 2024-08-28 03:19:22

uva 1611:Crane(构造 Grade D)的相关文章

UVa 1611 Crane (构造+贪心)

题意:给定一个序列,让你经过不超过9的6次方次操作,变成一个有序的,操作只有在一个连续区间,交换前一半和后一半. 析:这是一个构造题,我们可以对第 i 个位置找 i 在哪,假设 i  在pos 位置,那么如果 (pos-i)*2+i-1 <= n,那么可以操作一次换过来, 如果不行再换一种,如果他们之间元素是偶数,那么交换 i - pos,如果是奇数,交换 i - pos+1,然后再经过一次就可以换到指定位置. 代码如下: #pragma comment(linker, "/STACK:1

Uva 1611 Crane

Thinking about it: 对于一个长度为N的序列,最大的数字为N,那么如果要将它放回到第N个位置,那么最多需要2步. 先用例子简单证明一下: 假设序列:1 2 3 6 5 4,当前最大数为6,需要和4交换位置,那么可以看作:* * * 6 * 4,因为6和4之间有一个数,而6之前有三个数,那么可以之间把6之后的部分,与6(包括)之前的     等长部分交换,可得 : 1 2 5 4 3 6,此时只需要一步,即可.   若如果,6之前的数 小于 6与4之间的数呢,如 1 6 2 3 4

UVA 1611 Crane 起重机

题意:给一个1~n排列,1<=n<=10000,每次操作选取一个长度为偶数的连续区间.交换前一半和后一半,使它变成升序. 题解:每次只要把最小的移动到最左边,那么问题规模就缩小了.假设当前区间为[l,r],不难发现,只要最小的数字在[l,l+(r+1-l)/2]这个区间内,一定可以通过一次交换把最小的数字移动到l处,否则,先一定可以一次交换把最小的数字移动到上述区间中. #include<bits/stdc++.h> using namespace std; const int m

UVA - 1611 Crane 推理 + 贪心

题目大意:输入一个1-n的排列,要求经过操作将其变换成一个生序序列.操作的规则如下 每次操作时,可以选一个长度为偶数的连续区间,交换前一半和后一半 提示:2n次操作就足够了 解题思路:这句提示是关键,2n次操作,表明每个数最多只需要两次操作. 应该从左到右依次操作过去,先将前面的数安定好了,就可以不用管前面的数了 假设操作到第i个位置,而i这个数刚好在pos这个位置上,现在就要判断一下能否直接将pos上的i经过操作调到i这个位置上 如果 i + (pos - i) * 2 - 1 <= n 就表

UVa 1611 (排序 模拟) Crane

假设数字1~i-1已经全部归位,则第i到第n个数为无序区间. 如果i在无序区间的前半段,那么直接将i换到第i个位置上. 否则先将i换到无序区间的前半段,再将i归位.这样每个数最多操作两次即可归位. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 10000 + 10; 5 int a[maxn]; 6 vector<pair<int, int> > ans; 7 8 void

UVA 1589:Xiangqi (模拟 Grade D)

题目: 象棋,黑棋只有将,红棋有帅车马炮.问是否死将. 思路: 对方将四个方向走一步,看看会不会被吃. 代码: 很难看……WA了很多发,还越界等等. #include <cstdio> #include <cstring> #include <cstdlib> char graph[13][13]; int go[4][2] = {{1,0},{0,1},{-1,0},{0,-1}}; bool inBlackPalace(int x, int y) { return

(白书训练计划)UVa 1605 Building for UN(构造法)

题目地址:UVa 1605 一道答案特判的题.最简单的方法是只构造两层,第一层中第i行全是i国家,第二层中第i列全是i国家.这样就保证了所有的国家都会相邻. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h&

Uva 12009 平方数尾数与自身相同 dfs 构造

题目链接:点击打开链接 题意:rt 思路:从最低位开始构造,若x位的平方数是自身则继续构造. mark: #pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack>

UVa 12118 nspector&#39;s Dilemma (构造+DFS+欧拉回路)

题意:给定n个点,e条边和每条边的长度t,每两个点之间都有路相连,让你求一条最短的路经过这e条边. 析:刚开始想到要判连通,然后把相应的几块加起来,但是,第二个样例就不过,后来一想,那么有欧拉回路的还得加1啊. 又想每次再判一次是不是欧拉回路,怎么判又是问题,因为并不知道哪些是连在一块的,还得再查找,麻烦啊.... 后来上网看了一下题解,原来是要构造啊,也就是说把每个连通块都构造成一个欧拉回路,那么再减去端点的,就能完全连通了. 真是好方法,欧拉回路满足每个点的度都是偶数,也就是说如果不是偶数那