P10068 [CCO 2023] Line Town

考察符号的变化,如果是一正一负那么不会变,否则是两位一起奇偶翻转。把奇数位的符号翻转后,每个数可以认为是一个绝对值和符号的二元组。

对于序列最终的形态,其一定是一段负然后一些 \(0\) 再一段正,翻转后就是一段前缀 \(+-+-\cdots\),一段后缀 \(+-+-\cdots +(-)\),最后一位的正负号已知。同时前缀的绝对值递减,后缀的绝对值递增。注意前缀和后缀可以为空。

考虑按绝对值从大往小插数,同时记录 \(f_{0/1,0/1}\) 为当前序列左右分别要求的符号。

转移枚举分别有多少个数放在左右。贡献可以拆成距离和,同侧贡献和异侧贡献。变化量可以用 \(O(1)\) 次二分计算,写起来较为复杂。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int> ;

const int kN = 5e5 + 5;
int n;
pii a[kN];
int ord[kN];
ll f[2][2];

struct BIT {
  int tr[kN];
  void Clear() {
    fill_n(tr, n + 3, 0);
  }
  void Update(int x, int v) {
    for(; x <= n; x += (x & -x)) tr[x] += v;
  }
  int Query(int x) {
    int ans = 0;
    for(; x; x &= (x - 1)) ans += tr[x];
    return ans;
  }
}bit;

void DP(int N, int l, int r) {
  vector<int> v[2];
  int dif = 0;
  for(int i = l; i <= r; i++) {
    int x = ord[i];
    bool f = a[x].second;
    v[f].push_back(bit.Query(x));
    f ? dif++ : dif--;
  }
  auto Calc = [&](int fs, int ft, int ns, int nt) -> ll {
    deque<int> p[2], q[2];
    int c[2][2];
    c[0][0] = v[0].size();
    c[0][1] = 0;
    c[1][0] = v[1].size();
    c[1][1] = 0;
    auto P = [&](bool f, int c) -> int {
      return f ? N - (2 * c - 1) + ft : N - 2 * (c - 1) - ft;
    };
    auto S = [&](bool f, int i, bool g) -> int {
      return g ? v[f][i + c[f][0]] : v[f][i]; 
    };
    auto T = [&](bool f, int i, bool g) -> int {
      return g ? q[f][i] : p[f][i];
    };
    for(int i = 0; i < c[0][0]; i++) {
      p[0].push_back(fs + 1 + 2 * i);
    }
    for(int i = 0; i < c[1][0]; i++) {
      p[1].push_back(2 - fs + 2 * i);
    }
    if(ft != nt) {
      c[ft][0]--, c[ft][1]++;
      p[ft].pop_back();
      q[ft].push_front(P(ft, c[ft][1]));
    }
    ll ans = 1e18;
    ll cost = 0;
    for(int i : {0, 1}) {
      for(int j = 0; j < c[i][0]; j++) {
        cost += v[i][j] - p[i][j];
      }
      for(int j = 0; j < c[i][1]; j++) {
        cost += q[i][j] - v[i][j + c[i][0]];
      }
    }
    for(int f : {0, 1}) for(int g : {0, 1}) for(int h : {0, 1}) {
      for(int i = 0; i < c[g][f]; i++) {
        int si = S(g, i, f), ti = T(g, i, f);
        int l = -1, r = c[!g][h], p = r;
        while(l + 1 < r) {
          int mid = (l + r) >> 1;
          (S(!g, mid, h) >= si) ? (p = r = mid) : (l = mid);
        }
        l = -1, r = c[!g][h];
        while(l + 1 < r) {
          int mid = (l + r) >> 1;
          (T(!g, mid, h) <= ti) ? (l = mid) : (r = mid);
        }
        int cnt = max(l - p + 1, 0);
        (f == h) ? (cost += cnt) : (cost -= cnt);
      }
    }
    while(1) {
      ans = min(ans, cost);
      if(!c[0][0] || !c[1][0]) break;
      {
        int i = c[0][0] - 1;
        int j = c[1][0] - 1;
        int si = S(0, i, 0), ti = T(0, i, 0);
        int sj = S(1, j, 0), tj = T(1, j, 0);
        cost += ((si <= sj) && (ti >= tj));
        cost += ((si >= sj) && (ti <= tj));
      }
      for(int f : {0, 1}) for(int g : {0, 1}) {
        int i = c[f][0] - 1;
        int si = S(f, i, 0), ti = T(f, i, 0);
        int l = -1, r = c[!f][g];
        while(l + 1 < r) {
          int mid = (l + r) >> 1;
          (S(!f, mid, g) >= si) ? (r = mid) : (l = mid);
        }
        int pl = l, pr = r;
        l = -1, r = c[!f][g];
        while(l + 1 < r) {
          int mid = (l + r) >> 1;
          (T(!f, mid, g) <= ti) ? (l = mid) : (r = mid);
        }
        int v = max(l - pr + 1, 0) + max(pl - r + 1, 0);
        g ? cost += v : cost -= v;
      }
      for(int t : {0, 1}) {
        cost -= v[t][c[t][0] - 1] - p[t][c[t][0] - 1];
        c[t][0]--, c[t][1]++;
        p[t].pop_back();
        q[t].push_front(P(t, c[t][1]));
        cost += q[t][0] - v[t][c[t][0]];
      }
      {
        int i = 0;
        int j = 0;
        int si = S(0, i, 1), ti = T(0, i, 1);
        int sj = S(1, j, 1), tj = T(1, j, 1);
        cost -= ((si <= sj) && (ti >= tj));
        cost -= ((si >= sj) && (ti <= tj));
      }
      for(int f : {0, 1}) for(int g : {0, 1}) {
        int i = 0;
        int si = S(f, i, 1), ti = T(f, i, 1);
        int l = -1, r = c[!f][g];
        while(l + 1 < r) {
          int mid = (l + r) >> 1;
          (S(!f, mid, g) >= si) ? (r = mid) : (l = mid);
        }
        int pl = l, pr = r;
        l = -1, r = c[!f][g];
        while(l + 1 < r) {
          int mid = (l + r) >> 1;
          (T(!f, mid, g) <= ti) ? (l = mid) : (r = mid);
        }
        int v = max(l - pr + 1, 0) + max(pl - r + 1, 0);
        g ? cost += v : cost -= v;
      }
    }
    return ans;
  };
  ll tf[2][2];
  memcpy(tf, f, sizeof(tf));
  memset(f, 0x3f, sizeof(f));
  for(int fs : {0, 1}) for(int ft : {0, 1}) {
    if(tf[fs][ft] > 1e16) continue;
    for(int ns : {0, 1}) for(int nt : {0, 1}) {
      int nd[2] = {0, 0};
      if(fs != ns) nd[fs]++;
      if(ft != nt) nd[ft]++;
      if(nd[1] - nd[0] != dif) continue;
      f[ns][nt] = min(f[ns][nt], tf[fs][ft] + Calc(fs, ft, ns, nt));
    }
  }
  for(int i = l; i <= r; i++) bit.Update(ord[i], -1);
}

int main() {
//  freopen("1.in", "r", stdin);
//  freopen("1.out", "w", stdout);
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n;
  for(int i = 1; i <= n; i++) {
    int x;
    cin >> x;
    a[i] = pii {abs(x), (x > 0) ^ (i & 1)};
  }
  iota(ord + 1, ord + n + 1, 1);
  stable_sort(ord + 1, ord + n + 1,
    [&](int x, int y) { return a[x] > a[y]; });
  for(int i = 1; i <= n; i++) bit.Update(i, 1);
  memset(f, 0x3f, sizeof(f));
  f[1][(n & 1) ^ 1] = 0;
  for(int rem = n, l = 1, r; l <= n; l = r + 1) {
    pii val = a[ord[l]];
    if(!val.first) break;
    for(r = l; r < n; r++) {
      pii nxt = a[ord[r + 1]];
      if(val.first != nxt.first) break;
    }
    DP(rem, l, r);
    rem -= (r - l + 1);
  }
  ll ans = 1e18;
  for(int i : {0, 1}) {
    for(int j : {0, 1}) ans = min(ans, f[i][j]); 
  }
  cout << ((ans > 1e16) ? -1 : ans) << "\n";
  return 0;
}
posted @ 2025-10-08 15:54  CJzdc  阅读(10)  评论(0)    收藏  举报