[SDOI2015]排序

此题一看就有点像快排,先对最小一层操作,逐次向上,直到完成。

考虑如何操作,对于每一层(长度为2^x),暴力找出每段是否排好序,如果不是,num++,

对于每一层,如果num>2显然无解,因为上一层已经排好,将其分成两段,暴力调换,如果可以,继续枚举

最后发现操作顺序无关(显然),每次加上操作数的阶乘

太暴力了,没什么优化

#include <cstdio>
using namespace std;
int n,num,ans;
int bin[15]={1},kk[15]={1},a[5000];
int sum;
bool check(int l,int r) {
    if (l==r) return 1;
    for (int i=l+1;i<=r;i++)
        if (a[i]<a[i-1] || a[i]-a[i-1]>1) return 0;
    return 1;
}
bool swap(int l,int h,int ln) {
    int b[5000];
    for (int i=0;i<ln;i++)
        b[i]=a[l+i];
    for (int i=0;i<ln;i++)
        a[l+i]=a[h+i];
    for (int i=0;i<ln;i++)
        a[h+i]=b[i];
}
void dfs(int x) {
    int nu=0;int p[100];
    for (int i=1;i<=bin[n];i+=bin[x]) {
        if (!check(i,i+bin[x]-1)) p[++nu]=i,p[++nu]=i+bin[x-1];
    }
    if (nu>4) return;
    if (nu==0) {
        if (x!=n) dfs(x+1);
        else ans+=kk[sum];
    }
    else if (nu==2) {
        sum++;
        swap(p[1],p[2],bin[x-1]);
        if (check(p[1],p[1]+bin[x]-1)) {
            if (x==n) ans+=kk[sum];
            else dfs(x+1);
        }
        sum--;
        swap(p[1],p[2],bin[x-1]);
        return;
    }
    else if (nu==4) {
        sum++;
        for (int i=1;i<=2;i++)
            for (int j=3;j<=4;j++) {
                swap(p[i],p[j],bin[x-1]);
                if (check(p[1],p[1]+bin[x-1]-1) && check(p[3],p[3]+bin[x-1]-1)) {
                    if (x==n) ans+=kk[sum];
                    else dfs(x+1);
                }
                swap(p[i],p[j],bin[x-1]);
            }
        sum--;
    }
}
int main () {
//	freopen("hh.in","r",stdin);
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        bin[i]=bin[i-1]*2,kk[i]=kk[i-1]*i;
    for (int i=1;i<=bin[n];i++)
        scanf ("%d",&a[i]);
    dfs(1);
    printf("%d",ans);
}


猜你喜欢

转载自blog.csdn.net/qq_41893580/article/details/80208527