• [USACO18OPEN]Out of Sorts G


    描述

    传送门:P4375

    传送门:UPC6347

    留意着农场之外的长期职业生涯的可能性,奶牛Bessie开始在不同的在线编程网站上学习算法。

    她到目前为止最喜欢的算法是“冒泡排序”。这是Bessie的对长度为 NN 的数组 AA进行排序的奶牛码实现。

    1
    2
    3
    4
    5
    6
    7
    8
    sorted = false
    while (not sorted):
    sorted = true
    moo
    for i = 0 to N-2:
    if A[i+1] < A[i]:
    swap A[i], A[i+1]
    sorted = false

    显然,奶牛码中的“moo”指令的作用只是输出“moo”。奇怪的是,Bessie看上去执着于在她的代码中的不同位置使用这个语句。

    在用若干个数组测试了她的代码之后,Bessie得到一个有趣的观察现象:大的元素很快就会被拉到数组末尾,然而小的元素需要很长时间“冒泡”到数组的开头(她怀疑这就是为什么这个算法得名的原因)。为了实验和缓解这一问题,Bessie试着修改了她的代码,使代码在每次循环中向前再向后各扫描一次,从而无论是大的元素还是小的元素在每一次循环中都有机会被拉较长的一段距离。她的代码现在是这样的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    sorted = false
    while (not sorted):
    sorted = true
    moo
    for i = 0 to N-2:
    if A[i+1] < A[i]:
    swap A[i], A[i+1]
    for i = N-2 downto 0:
    if A[i+1] < A[i]:
    swap A[i], A[i+1]
    for i = 0 to N-2:
    if A[i+1] < A[i]:
    sorted = false

    给定一个输入数组,请预测Bessie的代码会输出多少次“moo”。

    输入

    输入的第一行包含 NN ( 1≤N≤100,0001≤N≤100,000 )。接下来 NN行描述了 A[0]A[N1]A[0]…A[N−1] ,每个数都是一个范围为 0… 109109的整数。输入数据不保证各不相同。

    输出

    输出“moo”被输出的次数。

    样例

    输入

    5
    1
    8
    5
    3
    2

    输出

    2

    思路

    1. 首先,每一次while()循环都会有两个跑错位置的数回到自己应该在的位置
      • 以样例为例
      • 1 8 5 3 2
      • 1 2 5 3 8 <—- 一次 while()循环之后 8跟2回到了自己应该在的位置
      • 1 2 3 5 8 <—- 两次while()循环之后
    2. 我们定义一个名词“分割线”(恰好将一半跑到前边的大数跟一半跑到后边的大数分隔开) 
      • 例如:样例中的55和33中间
      • 分割线所在的位置在多次while()循环时一直是固定的(可以自己模拟几次试试)
      • 线注意:分割线的位置我们是不知道具体在哪的,并且也不需要求出来它在哪,我们只需要遍历一遍就好了
      1. 然后我们将输入的数据进行离散化,用a[i].id来表示数据a[i].x应该在的位置
      2. 离散化完成后进行以下几步
        • 遍历一遍
        • 遍历的同时将a[i].ida[i].id加到树状数组中,bit[x]bit[x]表示[1,x][1,x]中有几个站对位置的数
        • sum(i)sum(i)求的是在[1,i][1,i]中有多少站对位置的数
        • isum(i)i−sum(i)表示[1,i][1,i]中有多少没站对位置的数
        • 线站对位置:本应在分割线后边的数老老实实呆在后边
        • 便本应在后边的数跑到前边来便是没站对位置
        • isum(i)i−sum(i)的最大值
    3. 特殊情况:不需要排序
      • 有可能所有的数全部相等(不保证没有重复的数)
      • 本身有序(11  22  33  44  55)
        while()1max(ans,1)特殊情况下while()循环运行的最小次数仍为1,用max(ans,1)即可解决

    代码

     1 /*
     2  * =========================================================================
     3  *
     4  *       Filename:  E.cpp
     5  *
     6  *           Link:  https://www.luogu.org/problemnew/show/P4375 
     7  *           
     8  *        Version:  1.0
     9  *        Created:  2018/07/22 12时21分29秒
    10  *       Revision:  none
    11  *       Compiler:  g++
    12  *
    13  *         Author:  杜宁元 (https://duny31030.github.io/), duny31030@126.com
    14  *   Organization:  QLU_浪在ACM
    15  *
    16  * =========================================================================
    17  */
    18 #include <bits/stdc++.h>
    19 using namespace std;
    20 #define ll long long
    21 #define max3(a,b,c) fmax(a,fmax(b,c))
    22 #define ios ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    23 const double eps = 1e-6;
    24 const int INF = 0x3f3f3f3f;
    25 const int N = 100010;
    26 int bit[N+1];   // bit[i]表示排好序之后有多少个数在[1,i]内
    27 int n;
    28 struct node
    29 {
    30     int x,id;
    31 }a[N+1];
    32 
    33 void add(int i,int x)
    34 {
    35     while(i <= n)
    36     {
    37         bit[i] += x;
    38         i += (i&-i);
    39     }
    40 }
    41 
    42 int sum(int i)
    43 {
    44     int s = 0;
    45     while(i > 0)
    46     {
    47         s += bit[i];
    48         i -= (i&-i);
    49     }
    50     return s;
    51 }
    52 
    53 bool cmp(const node a,const node b)
    54 {
    55     return a.x < b.x || (a.x == b.x && a.id < b.id);
    56 }
    57 
    58 int main()
    59 {
    60     ios
    61 #ifdef ONLINE_JUDGE 
    62 #else 
    63     freopen("in.txt","r",stdin);
    64     // freopen("out.txt","w",stdout); 
    65 #endif
    66     int ans = -99;
    67     cin >> n;
    68     for(int i = 1;i <= n;i++)
    69     {
    70         cin >> a[i].x;
    71         a[i].id = i;
    72     }
    73     sort(a+1,a+n+1,cmp);
    74     for(int i = 1;i <= n;i++)
    75     {
    76         add(a[i].id,1);
    77         ans = max(ans,i-sum(i));
    78     }
    79     printf("%d",max(ans,1));
    80     fclose(stdin);
    81     // fclose(stdout);
    82     return 0;
    83 }
  • 相关阅读:
    DLinq[新特性]
    破解 iPod Touch[转]
    iPod Touch Online
    谈到Model View Presenter模式之后的随笔[讨论版]
    各家银行买"基金"如何省钱
    WF随笔系列之二 架构、编译、序列化
    JavaScript AppendChild 引发的思考
    IEquatable接口
    DLinq查询
    基金小窍门:如何判断基金的赚与赔
  • 原文地址:https://www.cnblogs.com/duny31030/p/14304177.html
Copyright © 2020-2023  润新知