社区讨论

站外题贪心求证(悬三关)

学术版参与者 5已保存回复 10

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
10 条
当前快照
1 份
快照标识符
@lufjp88s
此快照首次捕获于
2024/03/31 21:16
2 年前
此快照最后确认于
2024/03/31 21:39
2 年前
查看原帖
题目大意:
给定一个长度为 nn 的数组 aa,你可以将任意数加一,不限次数,求最终排列里的逆序对的最少数量。
思路:
先离散化,如果 aia_i 加一,那么逆序对的数量必然会增加减少等于 ai+1a_i+1 的数的个数(设其为 frifr_i),增加后面等于 aia_i 的数的个数(设其为 bcibc_i),贪心如果 fri>bcifr_i>bc_i,那么将 aia_i 加一,初始逆序对用树状数组维护。
代码:
CPP
#include <bits/stdc++.h>

using namespace std;
using LL = long long;
using PII = pair<LL, LL>;

const LL kMaxN = 1e6 + 5;

LL n, idx, ans, a[kMaxN], fr[kMaxN], bc[kMaxN], b[kMaxN], cnt[kMaxN];

template <class T>
struct BIT {
  T c[kMaxN] = {0};
  T query(LL x) {
    T sum = 0;
    for (; x; x -= x & -x) {
      sum += c[x];
    }
    return sum;
  }
  void update(LL x, T s) {
    for (; x <= 2e5; x += x & -x) {
      c[x] += s;
    }
  }
};

signed main() {
  cin >> n;
  for (LL i = 1; i <= n; i++) {
    cin >> a[i];
    b[++idx] = a[i];
  }
  sort(b + 1, b + idx + 1);
  for (LL i = 1; i <= n; i++) {
    a[i] = lower_bound(b + 1, b + idx + 1, a[i]) - b;
  }
  for (LL i = n; i; i--) {
    bc[i] = cnt[a[i]], cnt[a[i]]++;
  }
  memset(cnt, 0, sizeof cnt);
  BIT<LL> tr;
  for (LL i = 1; i <= n; i++) {
    ans += i - 1 - tr.query(a[i]);
    tr.update(a[i], 1);
  }
  for (LL i = 1; i <= n; i++) {
    fr[i] = cnt[a[i] + 1];
    if (fr[i] > bc[i]) {
      ans = ans - fr[i] + bc[i];
    }
    cnt[a[i] + (fr[i] > bc[i])]++;
  }
  cout << ans;
  return 0;
}
当然巨佬们有更好解法发在楼下。

回复

10 条回复,欢迎继续交流。

正在加载回复...