zoukankan      html  css  js  c++  java
  • JZOJ 3462. 【NOIP2013模拟联考5】休息(rest)

    Description

    休息的时候,可以放松放松浑身的肌肉,打扫打扫卫生,感觉很舒服。在某一天,某LMZ 开始整理他那书架。已知他的书有n 本,从左到右按顺序排列。他想把书从矮到高排好序,而每一本书都有一个独一无二的高度Hi。他排序的方法是:每一次将所有的书划分为尽量少的连续部分,使得每一部分的书的高度都是单调下降,然后将其中所有不少于2 本书的区间全部翻转。重复执行以上操作,最后使得书的高度全部单调上升。可是毕竟是休息时间,LMZ 不想花太多时间在给书排序这种事上面。因此他划分并翻转完第一次书之后,他想计算,他一共执行了多少次翻转操作才能把所有的书排好序。LMZ 惊奇地发现,第一次排序之前,他第一次划分出来的所有区间的长度都是偶数。
     

    Input

    第一行一个正整数n, 为书的总数。

    接下来一行n个数,第i个正整数Hi,为第i 本书的高度。

    Output

    仅一个整数,为LMZ 需要做的翻转操作的次数。
     

    Sample Input

    6
    5 3 2 1 6 4

    Sample Output

    3
    【样例解释】
    第一次划分之后,翻转(5,3,2,1),(6,4)。之后,书的高度为1 2 3 5 4 6,然后便是翻转(5,4)即可。
     
     
    做法:

    一个并不明显的性质是,在对原序列进行第一次划分过后,以后
    的每次划分得到的各个部分都恰好由两个数组成。 这是因为在第一次划分和
    第一轮的翻转之后,原数列由若干个单调增序列拼接而成,形式如下:a1, a2…
    ai, b1, b2…bj…z1…zk.考虑相邻两个部分,不妨设为 a 部分和 b 部分,其中 ai
    和 b1前后相邻。若 ai<b1则可以合并成同一部分,否则会形成块(ai, b1),并
    且在下一轮翻转,成为…ai-1, b1, ai, b2…。可以发现在这以后,由于有 ai-1<ai,
    则 ai-1与 ai不会在同一个块里;同理 b1和 b2不会在同一个块里。即,任意连
    续三个数必定不会是单调递减的。 那么,这以后每次翻转都只会将相邻的逆
    序对交换。由于这个算法最终可以正确地得到结果,所以第一轮以后进行的
    翻转操作数就等于第一轮之后序列的逆序对数。而第一轮的翻转数我们可以
    直接模拟得到。 求一个序列的逆序对数的经典做法是归并排序,同时记录。
    时间复杂度 O(nlog2n)

    代码如下:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #include <string>
     5 #include <algorithm>
     6 #include <cmath>
     7 #define N 100007
     8 #define LL long long
     9 using namespace std;
    10 int n, a[N], b[N], tot;
    11 LL ans;
    12 
    13 void cl(int l, int r)
    14 {
    15     for (int i = l; i >= r; i--)
    16     a[++tot] = b[i];
    17     ans++;
    18 }
    19 
    20 inline void merge(int l, int mid, int r)
    21 {
    22     int i = l, j = mid + 1;
    23     for (int k = l; k <= r; k++)
    24         if (j > r || i <= mid && a[i] < a[j])    b[k] = a[i++];
    25         else b[k] = a[j++], ans += mid - i + 1;
    26     for (int k = l; k <= r; k++)    a[k] = b[k];
    27 }
    28 
    29 inline void mergeSort(int a, int b)
    30 {
    31     int mid = (a + b) / 2;
    32     if (a < b)
    33     {
    34         mergeSort(a, mid);
    35         mergeSort(mid + 1, b);
    36         merge(a, mid, b); 
    37     }
    38 }
    39 
    40 int main()
    41 {
    42     scanf("%d", &n);
    43     for (int i = 1; i <= n; i++)
    44         scanf("%d", &b[i]);
    45     int i = 1, j = 1;
    46     while (i <= n)
    47     {
    48         while (b[i] > b[i + 1] && i < n)    i++;
    49         cl(i, j);
    50         j = i + 1;
    51         i++;
    52     }
    53     memset(b, 0 ,sizeof(b));
    54     mergeSort(1, n);
    55     cout << ans;
    56 }
    View Code
  • 相关阅读:
    [Vue] #常见开发场景 #条件渲染#手动挂载 #组件方法的值驱动执行
    [JS高程] Typed Array 定型数组
    [JS高程]JavaScript中的RegExp对象
    [JS高程] Map 和 Set
    [JS高程] JavsScript 常用数组方法总结
    [JS高程] 字符串模式匹配方法
    自动化集成:Pipeline整合Docker容器
    自动化集成:Docker容器入门简介
    自动化集成:Jenkins管理工具详解
    分布式系统中,权限设计实践
  • 原文地址:https://www.cnblogs.com/traveller-ly/p/9338621.html
Copyright © 2011-2022 走看看