BZOJ3990 排序

题目:www.lydsy.com/JudgeOnline/problem.php?id=3990

这题很不错。

刚开始时无从下手,想了好多$O((2^n)log(2^n))$ 的idea,但是都不行。

后来去看题解发现操作序列是满足交换率的,然后竟然是搜索。

因为swap是swap的逆运算(歪歪的)

然后只要从小到大枚举操作序列就可以了。

这样类似分治下去,当你在计算长度为$2^i$的序列时已经保证了所有长度为$2^{i-1}$的序列的「连续且递增」。

注意是「连续且递增」,开始W了好多发,然后推掉重写(开抄) 呜呜。

好像可以证明是$O(n cdot 2^{2n})$ ?

以后见到这种操作数很小的题目要想想搜索,就算是暴力也可以多拿分。

#include <cstdio>
#include <cstring>
#include <vector>

#define LL long long
#define N 13

using namespace std;

int n;
LL fact[21],ans;

void change(vector<int> &x,int l1,int l2,int len){
    for(int i=0;i<len;i++)
        swap(x[l1+i],x[l2+i]);
}

bool check(vector<int> x,int l,int len){
    for(int i=1;i<len;i++)
        if(x[l+i]!=x[l+i-1]+1) return 0;
    return 1;
}

void dfs(vector<int> x,int t,int now){
    if(t==n){
        ans+=fact[now];
        return;
    }
    int tot=0,a[5];
    for(int i=0;i<(1<<n);i+=(1<<(t+1)))
        if(!check(x,i,1<<(t+1))){
            if(tot==4) return;
            a[++tot]=i; a[++tot]=i+(1<<t);
        }
    vector<int> b;
    if(!tot) dfs(x,t+1,now);
    if(tot==2){
        if(x[a[2]]+(1<<t)==x[a[1]]){
            b=x;
            change(b,a[1],a[2],1<<t);
            dfs(b,t+1,now+1);
        }
    }
    if(tot==4){
        if(x[a[1]]+(1<<t)==x[a[3]] && x[a[2]]+(1<<t)==x[a[4]]){
            b=x;
            change(b,a[2],a[3],1<<t);
            dfs(b,t+1,now+1);
        }
        if(x[a[1]]+(1<<t)==x[a[4]] && x[a[3]]+(1<<t)==x[a[2]]){
            b=x;
            change(b,a[2],a[4],1<<t);
            dfs(b,t+1,now+1);
        }
        if(x[a[3]]+(1<<t)==x[a[2]] && x[a[1]]+(1<<t)==x[a[4]]){
            b=x;
            change(b,a[1],a[3],1<<t);
            dfs(b,t+1,now+1);
        }
        if(x[a[4]]+(1<<t)==x[a[2]] && x[a[3]]+(1<<t)==x[a[1]]){
            b=x;
            change(b,a[1],a[4],1<<t);
            dfs(b,t+1,now+1);
        }
    }
}

vector<int> a;

int main(){
    scanf("%d",&n);
    a.resize(1<<n);
    for(int i=0;i<(1<<n);i++) scanf("%d",&a[i]);
    fact[0]=1;
    for(int i=1;i<=18;i++) fact[i]=fact[i-1]*(LL)i;
    dfs(a,0,0);
    printf("%lld
",ans);
    return 0;
}
View Code