Gym 102082G What Goes Up Must Come Down(树状数组求逆序数)
题目大意
给n个数,你要把这n个数排列成前k个不降序,后n-k个不升序,只能交换相邻的两个数,问最小的交换次数。
解题思路
对于每个数,他只有两个选择,要么排在左面,要么排在右面,所以开两个树状数组,计算这个数排到左面和排到右面需要的最小交换次数,然后取最小值就行了。
代码
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+10;
const int maxm = 2e5+10;
const int MAX = 100000;
int arr[maxn], c1[maxn], c2[maxn];
ll pre[maxn], post[maxn];
void add(int c[], int x) {
while(x<=MAX) {
++c[x];
x += x&-x;
}
}
int ask(int c[], int x) {
int sum = 0;
while(x) {
sum += c[x];
x -= x&-x;
}
return sum;
}
int main() {
int n; cin >> n;
for (int i = 1; i<=n; ++i) cin >> arr[i];
for (int i = 1; i<=n; ++i) {
pre[i] = ask(c1, MAX)-ask(c1, arr[i]);
add(c1, arr[i]);
}
for (int i = n; i>=1; --i) {
post[i] = ask(c2, MAX)-ask(c2, arr[i]);
add(c2, arr[i]);
}
ll ans = 0;
for (int i = 1; i<=n; ++i) ans += min(pre[i], post[i]);
cout << ans << endl;
return 0;
}