[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);
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址