P4375 [USACO18OPEN]Out of Sorts G 题解

Description

洛谷传送门

Solution

一道很巧妙的结论题。

我们观察到题目中是一个双向冒泡排序。然后问你要进行多少轮才能排好序。

我们首先对于原数组进行离散化。

考虑冒泡排序的过程(假设当前数组未排好序):

  • 第一次:找出一个最大值放到最后面。

    对于位置 \(x\),冒泡之后一定有一个大于 \(x\) 的数被放到了 \(x\) 后面。

  • 第二次:找出一个最小值放到最前面。

    同理,对于位置 \(x\),一定有一个小于等于 \(x\) 的值放到了 \(x\) 的前面。

这样一来,相当于把 \(x\) 前面的一个大于它的数和它后面一个小于等于它的数交换了。

因此,结论就是:$$ans = max(ans, x 前面大于 x 的数的个数)$$

用树状数组维护一下即可。

Code

#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;

inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

const int N = 1e5 + 10;
int n;
struct node{
    int pos, val;
    bool operator < (const node &b) const{
        return val != b.val ? val < b.val : pos < b.pos;
    }
}p[N];
int c[N];

inline void update(int x){
    for(; x <= n; x += x & (-x))
        c[x]++;
}

inline int query(int x){
    int res = 0;
    for(; x; x -= x & (-x))
        res += c[x];
    return res;
}

int main(){
    n = read();
    for(int i = 1; i <= n; ++i){
        p[i].val = read();
        p[i].pos = i;
    }
    sort(p + 1, p + 1 + n);
    int ans = 1;
    for(int i = 1; i <= n; ++i){
        update(p[i].pos);
        ans = max(ans, i - query(i));
    }
    printf("%d\n", ans);
    return 0;
}

End

posted @ 2021-10-27 18:04  xixike  阅读(122)  评论(0编辑  收藏  举报