首页 > 编程语言 > 详细

【洛谷P3322】排序

时间:2020-02-13 21:15:48      阅读:58      评论:0      收藏:0      [点我收藏+]

题目

题目链接:https://www.luogu.com.cn/problem/P3322
小A有一个\(1-2^N\)的排列\(A[1..2^N]\),他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的\(i(1<=i<=N)\),第i中操作为将序列从左到右划分为\(2^{N-i+1}\)段,每段恰好包括\(2^{i-1}\)个数,然后整体交换其中两段.
小A想知道可以将数组A从小到大排序的不同的操作序列有多少个,小A认为两个操作序列不同,当且仅当操作个数不同,或者至少一个操作不同(种类不同或者操作位置不同).
下面是一个操作事例: \(N=3,A[1..8]\)=\([3,6,1,2,7,8,5,4]\).
第一次操作,执行第3种操作,交换\(A[1..4]\)\(A[5..8]\),交换后的\(A[1..8]\)\([7,8,5,4,3,6,1,2]\).
第二次操作,执行第1种操作,交换\(A[3]\)\(A[5]\),交换后的\(A[1..8]\)\([7,8,3,4,5,6,1,2]\).
第三次操作,执行第2中操作,交换\(A[1..2]\)\(A[7..8]\),交换后的\(A[1..8]\)\([1,2,3,4,5,6,7,8]\).

思路

首先有一个明显的结论:对于一组合法的交换方案,任意调换操作顺序的最终结果是一样的。
所以我们可以从小到大搜索,最终方案数乘上操作次数的阶乘。
假设我们现在搜索到交换两个长度为\(2^k\)的序列,那么我们就将这一个序列划分成若干个长度为\(2^{k+1}\)的序列,显然我们需要满足在交换完两个区间后,每一个长度为\(2^{k+1}\)的序列要为一个公差为\(1\)的递增序列,这样我们才可能可以把它排好序。
那么假设对于所有的长度为\(2^{k+1}\)的序列,仅有1个不满足递增且连续,那么我们只需将这个序列前后两端长度为\(2^k\)调换,如果此时满足递增且连续,就继续往下搜索,否则该方案一定不成立。
如果有2个序列不满足递增且连续,我们就将这2个长度为\(2^{k+1}\)的序列分成的4个长度为\(2^k\)的序列,一共有4种交换方法,全部尝试一遍即可。
时间复杂度\(O(n\times 2^{2n})\)

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N=5000;
int n,a[N];
ll ans;

ll fac(int x)
{
    ll s=1;
    for (ll i=2;i<=x;i++) s*=i;
    return s;
}

bool check(int l,int r)
{
    for (int i=l+1;i<=r;i++)
        if (a[i-1]!=a[i]-1) return 0;
    return 1;
}

void Swap(int i,int j,int k)
{
    for (int l=1;l<=k;l++,i++,j++)
        swap(a[i],a[j]);
}

void dfs(int x,int k)
{
    if (x>n)
    {
        if (check(1,(1<<n))) ans+=fac(k);
        return;
    }
    int cnt=0,pos[5];
    for (int i=1;i<=(1<<n);i+=(1<<x))
        if (!check(i,i+(1<<x)-1))
        {
            pos[++cnt]=i;
            if (cnt>2) return;
        }
    if (cnt==1)
    {
        Swap(pos[1],pos[1]+(1<<x-1),(1<<x-1));
        if (check(pos[1],pos[1]+(1<<x)-1)) dfs(x+1,k+1);
        Swap(pos[1],pos[1]+(1<<x-1),(1<<x-1));
    }
    else if (cnt==2)
    {
        Swap(pos[1],pos[2],(1<<x-1));
        if (check(pos[1],pos[1]+(1<<x)-1) && check(pos[2],pos[2]+(1<<x)-1)) dfs(x+1,k+1);
        Swap(pos[1],pos[2],(1<<x-1));
        
        Swap(pos[1],pos[2]+(1<<x-1),(1<<x-1));
        if (check(pos[1],pos[1]+(1<<x)-1) && check(pos[2],pos[2]+(1<<x)-1)) dfs(x+1,k+1);
        Swap(pos[1],pos[2]+(1<<x-1),(1<<x-1));
        
        Swap(pos[1]+(1<<x-1),pos[2],(1<<x-1));
        if (check(pos[1],pos[1]+(1<<x)-1) && check(pos[2],pos[2]+(1<<x)-1)) dfs(x+1,k+1);
        Swap(pos[1]+(1<<x-1),pos[2],(1<<x-1));
        
        Swap(pos[1]+(1<<x-1),pos[2]+(1<<x-1),(1<<x-1));
        if (check(pos[1],pos[1]+(1<<x)-1) && check(pos[2],pos[2]+(1<<x)-1)) dfs(x+1,k+1);
        Swap(pos[1]+(1<<x-1),pos[2]+(1<<x-1),(1<<x-1));
    }
    else dfs(x+1,k);
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=(1<<n);i++)
        scanf("%d",&a[i]);
    dfs(1,0);
    printf("%lld",ans);
    return 0;
}

【洛谷P3322】排序

原文:https://www.cnblogs.com/stoorz/p/12304931.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!