https://codeforces.com/gym/102082
题意:给你一个序列,你每次操作可以交换两个相邻的数,问你最少多少次操作可以让这个序列变成一个单峰序列。
分析:对于一个序列,按照顺序标记为1-N,每次交换相邻的两个数,那么交换后的序列的逆序数对数量就是操作的最小值。
而此时我们是需要一个单峰的排列,那么最大的数一定在中间,次大的数一定是往两边放,那么此时就有两种情况,但是无论怎么放,对下一个要放进来的数的编号的逆序数是不影响的,因为不会插入到中间,只会放到到两边,即当前已经放好的编号中,大于或小于某一个数的数的数量是确定的。然后逆序数用树状数组维护即可。注意当有很多值相等的元素时需要将其一起放进去,即保证相等的数相互之间不交换
#include "bits/stdc++.h"
namespace fastIO {
#define BUF_SIZE 100000
bool IOerror = 0;
inline char nc() {
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if (p1 == pend) {
p1 = buf;
pend = buf + fread(buf, 1, BUF_SIZE, stdin);
if (pend == p1) {
IOerror = 1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
inline void read(int &x) {
char ch;
while (blank(ch = nc()));
if (IOerror) return;
for (x = ch - '0'; (ch = nc()) >= '0' && ch <= '9'; x = x * 10 + ch - '0');
}
#undef BUF_SIZE
};
using namespace fastIO;
using namespace std;
const int mod = 1e9 + 7;
int c[100004];
struct node {
int w, id;
bool friend operator<(node a, node b) {
return a.w > b.w;
}
} a[100004];
int lowbit(int x) {
return x & (-x);
}
void updata(int x, int d) {
while (x < 100004) {
c[x] += d;
x += lowbit(x);
}
}
int que(int x) {
int res = 0;
while (x > 0) {
res += c[x];
x -= lowbit(x);
}
return res;
}
int main() {
int n;
read(n);
memset(c, 0, sizeof(c));
for (int i = 1; i <= n; ++i) {
read(a[i].w);
a[i].id = i;
}
sort(a + 1, a + 1 + n);
long long ans = 0;
for (int i = 1; i <= n; ++i) {
int las = i;
while (a[las + 1].w == a[i].w)las++;
for (int j = i; j <= las; ++j) {
ans += min(que(a[j].id), i - 1 - que(a[j].id));
}
for (int j = i; j <= las; ++j) {
updata(a[j].id, 1);
}
i = las;
}
printf("%lld\n", ans);
}
。