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;
}