zoukankan      html  css  js  c++  java
  • [bzoj3990][SDOI2015]排序-搜索

    Brief Description

    小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认为两个操作序列不同,当且仅当操作个数不同,或者至少一个操作不同(种类不同或者操作位置不同).

    Algorithm Design

    首先不难发现操作顺序不影响答案, 我们只需要考察每种操作是否选中, 若选中交换哪两块就好了. 一个合法的操作序列如果有(n)个操作, 那么可以给答案(contribute n!). 我们从小到大考察每一种操作, 首先, 可以知道, 对于操作(2^i), 序列肯定已经被分成了(2^{n-i+1})个有序数列, 我们首先检查是否有序, 如果有问题直接(return). 然后扫描每个块, 每两个块都必须是有序的, 否则要交换. 如果(tot geqslant 4)那么一定不合法. 代码表达的非常清楚.

    Code

    #include <algorithm>
    #include <cstdio>
    #define ll long long
    const int maxn = 1 << 13;
    int n;
    int a[maxn];
    ll po[13];
    ll ans;
    bool check(int k) {
      for (int i = 1; i <= (1 << (n - k)); i++)
        if (a[(i - 1) * (1 << k) + 1] + (1 << (k - 1)) !=
            a[(i - 1) * (1 << k) + (1 << (k - 1)) + 1])
          return 0;
      return 1;
    }
    void swap(int i, int j, int k) {
      for (int m = 1; m <= k; m++)
        std::swap(a[i + m - 1], a[j + m - 1]);
    }
    void dfs(int now, int num) {
      if (now && !check(now))
        return;
      if (now == n) {
        ans += po[num];
        return;
      }
      dfs(now + 1, num);
      int tmp[5], tot = 0;
      for (int i = 1; i <= (1 << (n - now)); i += 2)
        if (a[i * (1 << now) + 1] != a[(i - 1) * (1 << now) + 1] + (1 << now)) {
          if (tot == 4)
            return;
          tmp[++tot] = i;
          tmp[++tot] = i + 1;
        }
      if (!tot)
        return;
      for (int i = 1; i <= tot; i++)
        for (int j = i + 1; j <= tot; j++) {
          swap((1 << now) * (tmp[i] - 1) + 1, (1 << now) * (tmp[j] - 1) + 1,
               1 << now);
          dfs(now + 1, num + 1);
          swap((1 << now) * (tmp[i] - 1) + 1, (1 << now) * (tmp[j] - 1) + 1,
               1 << now);
        }
    }
    int main() {
      // freopen("input", "r", stdin);
      po[0] = 1;
      for (int i = 1; i <= 12; i++)
        po[i] = po[i - 1] * i;
      scanf("%d", &n);
      for (int i = 1; i <= 1 << n; i++)
        scanf("%d", &a[i]);
      dfs(0, 0);
      printf("%lld", ans);
    }
    
  • 相关阅读:
    attr与prop
    Django框架学习
    库的操作
    javascript 基础知识
    进程
    正则表达式
    模块( collections , time , random , os , sys)
    内置函数
    生成器
    迭代器
  • 原文地址:https://www.cnblogs.com/gengchen/p/6593071.html
Copyright © 2011-2022 走看看