luoguP3322 [SDOI2015]並び替え

まず、我々は簡単に為替の任意のセクションの順序は解答には影響しません知ることができます。

だから我々は、インターバルの長さで検索することができます。

そして、各区間の長さは、一度だけ交換することができるので、我々は剪定することができるからです。

現在の検索インターバルの長さ\(X ^ 2 \) 我々は、各長さのためにすることができる\(2 ^ {X + 1 } \) が単調増加と隣接する二つの数間の差である場合間隔決定\ (1 \)でない場合は、その後、マークをマーク。

間隔がよりマークされている場合は、\(2 \) その後、どのような場合にはそれが(それについて考える、なぜ)直接バックソート、およびすることができません。

ここでは、議論のマーカー間隔の数を分割します:

  • \(0 \)評価:検索の直接次の層。

  • \(1 \) A:直接セクション半分に切断し、表裏の交換など。

    理由は単純です:一つのセクションに単調に増加する要件と隣接差分の2つの数の間の満たす必要があります\(1 \)の前に、限り交換をし、2後(あなたは数学的帰納のアイデアを使用することができます)することができます。

  • \(2 \) A:可能な場合、2つのセクション各ヘッド交換、エンドに交換端、交換の第一の端部、4例交換テールエンドを検討、検索が継続されます。

我々は階乗を蓄積するためにあらゆる可能な答えがかかります(\ ANS)\をすることができます。

#include<bits/stdc++.h>
#define il inline
#define rg register
#define gi read<int>
using namespace std;
const int O = 1 << 12 | 15;
template<class TT>
il TT read() {
    TT o = 0,fl = 1; char ch = getchar();
    while (!isdigit(ch) && ch != '-') ch = getchar();
    if (ch == '-') fl = -1, ch = getchar();
    while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
    return fl * o;
}
int n, a[O], anc[15][O], ans;
il void swapp(int & x, int & y) {x ^= y ^= x ^= y;}
il void Swap(int S1, int S2, int x) {
    for (int i = 0; i < 1 << x - 1; ++i)
        swapp(anc[x + 1][S1 + i], anc[x + 1][S2 + i]);
}
il void dfs(int, int);
il void Doit(int S1, int S2, int b1, int b2, int x, int num) {
    Swap(S1, S2, x);
    for (int i = 1; i < 1 << x; ++i) {
        if (anc[x + 1][b1 + i] - anc[x + 1][b1] != i) return Swap(S1, S2, x);
        if (anc[x + 1][b2 + i] - anc[x + 1][b2] != i) return Swap(S1, S2, x);
    }
    dfs(x + 1, num + 1);
    Swap(S1, S2, x);
}
il void dfs(int x, int num) {
    if (x == n + 1) {
        for (int i = 1; i <= 1 << n; ++i) if (anc[x][i] ^ i) return ;
        int res = 1;
        for (int j = 2; j <= num; ++j) res *= j;
        ans += res;
        return ;
    }
    int cnt = 0, S1, S2;
    for (int i = 1; i <= 1 << n; i += 1 << x)
        for (int j = 1; j < 1 << x; ++j)
            if (anc[x][i + j] != anc[x][i] + j) {
                if (cnt == 2) return ;
                if (cnt) S2 = i;
                else S1 = i;
                ++cnt; break;
            }
    for (int i = 1; i <= 1 << n; ++i) anc[x + 1][i] = anc[x][i];
    if (!cnt) return dfs(x + 1, num);
    if (cnt == 1) {
        Swap(S1, S1 + (1 << x - 1), x);
        dfs(x + 1, num + 1);
        return ;
    }
    Doit(S1, S2, S1, S2, x, num); Doit(S1 + (1 << x - 1), S2 + (1 << x - 1), S1, S2, x, num);
    Doit(S1, S2 + (1 << x - 1), S1, S2, x, num); Doit(S1 + (1 << x - 1), S2, S1, S2, x, num);
}
int main() {
    n = gi();
    for (int i = 1; i <= 1 << n; ++i) anc[1][i] = gi();
    dfs(1, 0);
    printf("%d\n", ans);
    return 0;
}

おすすめ

転載: www.cnblogs.com/lylyl/p/11762225.html