[USACO18OPEN] Out of Sorts P JZOJ 100136 冒泡的胖头鱼(冒泡排序性质)

题解:

显然对整个序列考虑不行,不如对每一个元素单独考虑。

一个元素x在x和x+1都成为分割点前显然会被一直计算答案,设\(T(x)\)表示x分割点出现的时间。

那么\(Ans=\sum_{i=1}^n max(T(i-1),T(i))\)

众所周知,冒泡排序都是去考虑每一个元素的往左移动,而不是往右移动。

对冒泡排序的一个元素\(a[i]\),若它前面有\(k\)个比他大的数,那么前\(k\)轮它都会往前移动一格。

对于这题,只要\(1..x\)的元素全部退到\(x\)以前,就有\(x\)这个分割点了。

所以设\(b[i]\)\(i\)大的元素所在的位置,\(T(x)=max(b[i]-x)(i\in[1,x])\)

这题有相同的元素,由于冒泡排序是稳定排序,所以相同的元素就考虑它们原来的位置就好了。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++)
#define ff(i, x, y) for(int i = x, _b = y; i <  _b; i ++)
#define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int N = 1e5 + 5;

int n, a[N], b[N], mx;
ll ans;

int cmpb(int x, int y) {
	if(a[x] == a[y]) return x < y;
	return a[x] < a[y];
}

int main() {
	scanf("%d", &n);
	fo(i, 1, n) scanf("%d", &a[i]), b[i] = i;
	sort(b + 1, b + n + 1, cmpb);
	int t1 = 0, t2;
	fo(i, 1, n) {
		mx = max(mx, b[i]);
		t2 = max(mx - i, 1);
		ans += max(t1, t2); t1 = t2;
	}
	pp("%lld\n", ans);
}
posted @ 2020-02-25 14:23  Cold_Chair  阅读(198)  评论(0编辑  收藏  举报