BZOJ3990 [SDOI2015] Sort【Search】

topic

Small A has a 1-2^N arrangement A[1..2^N], he wants to sort the A array from small to large, there are N kinds of operations that small A can perform, each operation can be performed at most once, for For all i(1<=i<=N), the i-th operation is to divide the sequence from left to right into 2^{N-i+1} segments, each segment contains exactly 2^{i-1} numbers , and then exchange two of them as a whole. Small A wants to know how many different operation sequences can sort array A from small to large. Small A thinks that the two operation sequences are different if and only if the number of operations is different, or at least one Different operations (different types or different operating locations).

The following is an operation example:
N=3,A[1..8]=[3,6,1,2,7,8,5,4].
The first operation, perform the third operation, exchange A[ 1..4] and A[5..8], the exchanged A[1..8] is [7, 8, 5, 4, 3, 6, 1, 2].
The second operation, execute the first 1 operation, swap A[3] and A[5], A[1..8] after the swap is [7, 8, 3, 4, 5, 6, 1, 2].
The third operation, execute In the second operation, exchange A[1..2] and A[7..8], the exchanged A[1..8] is [1, 2, 3, 4, 5, 6, 7, 8] .

input format

The first line, an integer N

The second line, 2^N integers, A[1..2^N]

output format

an integer representing the answer

input sample

3

7 8 5 6 1 2 4 3

Sample output

6

hint

100% data, 1<=N<=12.

answer

We can strongly guess that the order of operations can be arbitrary
Just try it and you'll find
Careful observation found that all operation intervals have only complete inclusion or disjointness. For two adjacent operations \(a\) and \(b\)
in a legal operation sequence , we try to exchange their order ① If \(a\ ) , \(b\) do not intersect, then obviously it has no effect ② If \(a\) , \(b\) intersect, then it must be a containment relationship, let’s set \(|a| < |b|\) If \ An operation interval of (a\) is in \(b\) , then swapping the two intervals in \(a\) before and after the operation \(b\) obviously does not change the order if the two operations of \(a\) The intervals are all in \(b\) , then the elements in these two intervals before and after the \(b\) operation are unchanged, we only need to find the original two intervals after the \(b\) operation to exchange , the final sequence remains unchanged




This roughly proves

Since the order is irrelevant, we can enumerate from the small.
Because large interval operations cannot affect its interior, we must ensure that the interior of the next level interval must be in +1 increasing order for each operation.
Specifically, for the first \(i\ ) operation, the length of the operation interval is \(2^{i - 1}\) , then we find all intervals of the \(i + 1\)th operation, if the interior is not incremented by +1, then this interval must be operated

If the number of such intervals \(>3\) , obviously we cannot take them all into account, and return directly.
If the number of such intervals is 1, then we only need to exchange the inside of this interval.
If the number of such intervals is 2, if there is a legal scheme, It must be to exchange one of the two sub-intervals \(2\) , there are a total of \(4\) in the situation, you can check one by one

Finally, if an operation set \(S\) is legal, it will contribute the number of solutions \(|S|!\)

If there is only one legal case for each layer, the total complexity \(O(n * 2^n)\)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 13,maxm = 10000,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int a[maxm],n,N,chs;
LL ans,fac[maxn];
bool isorder(int l,int len){
    for (int i = 1; i < len; i++) if (a[l + i] != a[l + i - 1] + 1) return false;
    return true;
}
void Swap(int u,int v,int len){
    for (int i = 0; i < len; i++) swap(a[u + i],a[v + i]);
}
void dfs(int dep){
    if (dep > n){
        if (isorder(1,N)) ans += fac[chs];
        return;
    }
    int len = 1 << dep,x = 0,y = 0;
    for (int i = 1; i <= N; i += len){
        if (!isorder(i,len)){
            if (!x) x = i;
            else if (!y) y = i;
            else return;
        }
    }
    if (!x && !y) dfs(dep + 1);
    else if (x && !y){
        chs++;
        Swap(x,x + (len >> 1),(len >> 1));
        dfs(dep + 1);
        Swap(x,x + (len >> 1),(len >> 1));
        chs--;
    }
    else if (x && y){
        chs++;
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 2; j++){
                Swap(x + i * (len >> 1),y + j * (len >> 1),(len >> 1));
                if (isorder(x,len) && isorder(y,len))
                    dfs(dep + 1);
                Swap(x + i * (len >> 1),y + j * (len >> 1),(len >> 1));
        }
        chs--;
    }
}
int main(){
    fac[0] = 1;
    for (int i = 1; i <= 12; i++) fac[i] = fac[i - 1] * i;
    n = read(); N = (1 << n);
    REP(i,N) a[i] = read();
    dfs(1);
    cout << ans << endl;
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325348819&siteId=291194637