2013-2014 ACM ICPC Central European Regional Contest (CERC 13) I题Crane

题目大意:

有n个数字的某种排列方式,每一次可以交换某个偶数长度区间左右两部分,比如341256可以交换前四个数字,交换后为123456,最终形成1、2、3、4……n的排列,要求步骤数不能超过9^6=531441,输出方案


这道题其实模拟一下就行了,依次按顺序把1、2、3、4等等换入对应位置

有两种情况要考虑,第一种:

2 1 3 4

可以直接通过交换前两个数字,把1换入第一个位置

第二种:

2 3 4 1

1的位置比较靠后,无法一步完成,比如先交换到第一种情况,再利用第一种换入正确的位置

step1:4 1 2 3   step2:1 4 2 3

需要留意下标的计算!!


按照这个思路 每个数字最多2步操作,时间复杂度大约是n方的,可以AC

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
int n;
int a[10001];
void work()
{
    vector<int> l,r;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==i) continue;
        int k=i+1;
        while(a[k]!=i) k++;
        int rest=n+1-i;
        if((k-i)*2>rest)
        {
            int half=rest/2;
            for(int p=n+1-half*2,q=n+1-half;q<=n;p++,q++)
            {
                swap(a[p],a[q]);
            }
            k-=half;
            l.push_back(n+1-half*2);
            r.push_back(n);
        }
        for(int p=i,q=k;p<k;p++,q++) swap(a[p],a[q]);
        l.push_back(i);
        r.push_back(k+k-i-1);
    }
    printf("%d\n",l.size());
    for(int i=0;i<l.size();i++) printf("%d %d\n",l[i],r[i]);
}
int main()
{
    //freopen("in.txt","r",stdin);
    int tc;
    scanf("%d",&tc);
    while(tc--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        work();
    }
    return 0;
}


你可能感兴趣的:(模拟,Crane,cerc)