zoukankan      html  css  js  c++  java
  • [BZOJ1330] Editing a Book

    题目链接:Editing a Book

    Description

    给定一个(1)~(n)的全排列,你可以每次选择其中一段区间,将其剪切,并黏贴到任意位置。
    问最少操作几次可以将这个排列变成 (1,2,...,n) 的形式。
    多组数据。
    数据范围 数据组数(le 50)(1le nle 9)
    时间限制 (20 Sec)

    Solution

    我们考虑(IDA*),每一次操作最多改变3个数字的后继。
    定义(h()=sum_{i=2}^{n} [num[i] != num[i-1]+1]),表示有多少个相邻对不满足顺序。
    那么,如果(h()>3(maxd-d)),代表进行完所有操作,并且每次操作都修改3个数字的后继,都不能满足条件,则立刻返回。
    爆搜即可。
    复杂度 (O(玄学))
    bzoj土豆机过于土豆,导致此代码本地能过,提交TLE。
    其实还有更优秀的做法,复杂度是(O(n^6 log(n!)))的,具体见(Claris)的博客。
    https://www.cnblogs.com/clrs97/p/6321773.html

    Code

    // Author: wlzhouzhuan
    #pragma GCC optimize(2)
    #pragma GCC optimize(3)
    #include <bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    #define ull unsigned long long
    #define rint register int
    #define rep(i, l, r) for (rint i = l; i <= r; i++)
    #define per(i, l, r) for (rint i = l; i >= r; i--)
    #define mset(s, _) memset(s, _, sizeof(s))
    #define pb push_back
    #define pii pair <int, int>
    #define mp(a, b) make_pair(a, b)
    
    inline int read() {
      int x = 0, neg = 1; char op = getchar();
      while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
      while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
      return neg * x;
    }
    inline void print(int x) {
      if (x < 0) { putchar('-'); x = -x; }
      if (x >= 10) print(x / 10);
      putchar(x % 10 + '0');
    }
    
    const int N = 10;
    int a[N], n, maxd, flag;
    
    int h() {
      int cnt = 0;
      for (rint i = 2; i <= n; i++) {
        if (a[i - 1] + 1 != a[i]) {
          cnt++;
        }
      }
      return cnt;
    }
    bool check() {
      for (rint i = 1; i <= n; i++) {
        if (a[i] != i) {
          return 0;
        }
      }
      return 1;
    }
    void dfs(int x) {
      if (flag) return ;
      if (check()) {
        flag = 1;
        return ;  
      }
      if (h() > 3 * (maxd - x)) {
        return ;
      }
      int b[10], c[10], len;
      for (rint i = 1; i <= n; i++) b[i] = a[i];
      for (rint le = 1; le <= n; le++) {
        for (rint ri = le; ri <= n; ri++) {
          len = 0;
          for (rint i = 1; i <= n; i++) if (i < le || i > ri) c[++len] = b[i];
          for (rint cut = 0; cut <= len; cut++) {
            int cur = 0;
            for (rint i = 1; i <= cut; i++) a[++cur] = c[i];
            for (rint i = le; i <= ri; i++) a[++cur] = b[i];
            for (rint i = cut + 1; i <= len; i++) a[++cur] = c[i];
            dfs(x + 1);
          }
        }
      }
    }
    int main() {
      while (~scanf("%d", &n) && n) {
        for (int i = 1; i <= n; i++) {
          a[i] = read();
        }
        flag = 0;
        for (maxd = 0; maxd <= 10; maxd++) {
          dfs(0);
          if (flag) break;
        }
        printf("%d
    ", maxd);
      }
      return 0;
    }
    
  • 相关阅读:
    单调队列+二分 G
    dp cf 1700 最近几天的刷题
    dp 20190618
    dp 20190617
    dp cf 20190615
    dp cf 20190614
    powercli
    zabbix docker-weixin
    cenetos-大文件排序
    esxcli命令
  • 原文地址:https://www.cnblogs.com/wlzhouzhuan/p/12755456.html
Copyright © 2011-2022 走看看