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;
}
posted @ 2021-02-01 21:27  shuitiangong  阅读(84)  评论(0编辑  收藏  举报