Problem p02667 (C++) — buggy submission, verdict: Time Limit Exceeded

#pragma GCC optimize("Ofast")
#define _USE_MATH_DEFINES
#include "bits/stdc++.h"

using namespace std;

using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;

constexpr char newl = '\\n';
constexpr double eps = 1e-10;

#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define F0R(i, b) FOR(i, 0, b)
#define RFO(i, a, b) for (int i = ((b)-1); i >= (a); i--)
#define RF0(i, b) RFO(i, 0, b)
#define fi first
#define se second
#define debug(x) cout << #x << ": " << x << '\\n';
#define rng(a) a.begin(), a.end()
#define rrng(a) a.rbegin(), a.rend()

template <typename T1, typename T2> inline void chmin(T1 &a, T2 b) {
  if (a > b)
    a = b;
}
template <typename T1, typename T2> inline void chmax(T1 &a, T2 b) {
  if (a < b)
    a = b;
}
template <class T> void Print(vector<T> v) {
  F0R(i, v.size()) { cout << v[i] << ' '; }
  cout << newl;
}

#if 1

// INSERT ABOVE HERE
signed main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  string T;
  cin >> T;

  // Tから1文字ずつ削除していく

  // 1文字削除した以降は、偶数列と奇数列が入れ替わる

  // 「この削除を行ったとき、奇数列の1を、いくつ増やすことができるか？」
  // これを A とおく、その数を各削除位置に対して計算する

  // A = そこより後（その位置を含まない）の偶数の数 -
  // そこ以降（その位置を含む）の奇数の数
  // Aが最大の部分を削除していけば良い（ただしAが最大で 1 と 0 があれば 0
  // を優先して消す）

  // ただし単純にAを計算するとO(N)かかり、N回削除だとO(N^2)で間に合わない

  //  o  e  o  e  o  e  o  e  o  e
  //  0  1  1  1  1  0  1  1  0  1 数列
  //     4     3     2     2     1 偶数列
  //   ／    ／    ／    ／    ／
  //  3     3     2     1     0    奇数列
  //  1  0  0  0  0  1  1  1  1  0 A

  //                 * ここを削除してみる

  //  o  e  o  e  o  e  o  e  o
  //  0  1  1  1  1  1  1  0  1 数列
  //     3     2     1     0    偶数列
  //   ／    ／    ／    ／    ／
  //  4     4     3     2     1 奇数列
  // -1 -2 -2 -2 -2 -2 -2 -1 -1 A

  // 削除位置以前は、範囲Add(Sub)
  // 削除位置以降は、位置が一つずれ減算順が逆になる

  //
  // 解けないので解説を読む…
  //

  // > まず，1 を削除するのは 0 を全て削除してからでいいです。というのも 0
  // がまだ残っているなら， 1 を削除する代わりにその 1 に最も近い 0
  // を削除することで，1 になっている箇所がより多い文字列 が得られるからです。

  // (a0個の 0) 1 (a1個の 0) 1 . . . 1 (ak個の 0)

  vector<int> zs;
  zs.push_back(0);

  // 偶数個の連続した1の数
  i64 eoc = 0;

  int prev = 0;
  int cnt = 0;
  T += '2';
  F0R(i, T.size()) {

    int n = T[i] - '0';

    if (n != prev) {
      if (prev == 1) {
        eoc += cnt & ~1;
        if (cnt & 1) {
          zs.push_back(0);
        }
        cnt = 0;
        prev = 0;
      } else if (prev == 0) {
        zs.back() += cnt;
        cnt = 0;
        prev = 1;
      }
    }
    cnt++;
  }

  // Print(zs);
  // debug(eoc);

  i64 result = 0;
  F0R(i, zs.size()) {

    // 削除すべき数
    int dc = i ? zs[i] - 1 : zs[i];

    if (dc <= 0)
      continue;

    // 0 を偶数個削除
    result += (i64)dc / 2 * (eoc + i * 2 + (zs.size() - i - 1));
    // debug(result);

    // 0 を1個削除
    if (dc & 1) {
      int n = 0;
      result += i + eoc / 2;
      F0R(j, zs.size() - 1) {
        n += zs[j] + 1;
        if (j < i)
          continue;
        if (n & 1)
          result++;
      }
    }
    // debug(result);

    zs[i] -= dc;
  }

  // 1個のこった0を右から順に削除
  // cout << "del <--0" << newl;
  RFO(i, 1, zs.size()) {
    if (zs[i]) {
      result += eoc / 2 + i;

      // ここより右の1の数
      int n = zs.size() - i - 1;
      result += (n + 1) / 2;
    }
  }

  // 残りは1だけなので順に削除
  int oc = eoc + zs.size() - 1;
  // debug(oc);
  // debug(result);
  //  1 2 3 4 5 6 ...
  //  1 1 2 2 3 3 ...

  if (oc & 1)
    result += (oc + 1) / 2;
  oc /= 2;
  result += ((i64)oc + 1) * oc;

  cout << result;
}
#endif


Error: TLE

Fixed submission:

#pragma GCC optimize("Ofast")
#define _USE_MATH_DEFINES
#include "bits/stdc++.h"

using namespace std;

using u8 = uint8_t;
using u16 = uint16_t;
using u32 = uint32_t;
using u64 = uint64_t;
using i8 = int8_t;
using i16 = int16_t;
using i32 = int32_t;
using i64 = int64_t;

constexpr char newl = '\\n';
constexpr double eps = 1e-10;

#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define F0R(i, b) FOR(i, 0, b)
#define RFO(i, a, b) for (int i = ((b)-1); i >= (a); i--)
#define RF0(i, b) RFO(i, 0, b)
#define fi first
#define se second
#define debug(x) cout << #x << ": " << x << '\\n';
#define rng(a) a.begin(), a.end()
#define rrng(a) a.rbegin(), a.rend()

template <typename T1, typename T2> inline void chmin(T1 &a, T2 b) {
  if (a > b)
    a = b;
}
template <typename T1, typename T2> inline void chmax(T1 &a, T2 b) {
  if (a < b)
    a = b;
}
template <class T> void Print(vector<T> v) {
  F0R(i, v.size()) { cout << v[i] << ' '; }
  cout << newl;
}

#if 1

// INSERT ABOVE HERE
signed main() {
  cin.tie(0);
  ios_base::sync_with_stdio(false);

  string T;
  cin >> T;

  int s = T.size();

  // Tから1文字ずつ削除していく

  // 1文字削除した以降は、偶数列と奇数列が入れ替わる

  // 「この削除を行ったとき、奇数列の1を、いくつ増やすことができるか？」
  // これを A とおく、その数を各削除位置に対して計算する

  // A = そこより後（その位置を含まない）の偶数の数 -
  // そこ以降（その位置を含む）の奇数の数
  // Aが最大の部分を削除していけば良い（ただしAが最大で 1 と 0 があれば 0
  // を優先して消す）

  // ただし単純にAを計算するとO(N)かかり、N回削除だとO(N^2)で間に合わない

  //  o  e  o  e  o  e  o  e  o  e
  //  0  1  1  1  1  0  1  1  0  1 数列
  //  3     3     2     1     0    奇数列
  //     4     3     2     2     1 偶数列
  //  1  0  0  0  0  1  1  1  1  0 A

  //                 * ここを削除してみる

  //  o  e  o  e  o  e  o  e  o
  //  0  1  1  1  1  1  1  0  1 数列
  //  4     4     3     2     1 奇数列
  //     3     2     1     0    偶数列
  // -1 -2 -2 -2 -2 -2 -2 -1 -1 A

  vector<int> os((s + 1) / 2), es(s / 2);

  int result = 0;

  while (T.size()) {

    int o = 0, e = 0;
    int best = INT32_MIN, bi;
    RF0(i, T.size()) {
      int n = T[i] - '0';
      if (!(i & 1)) {
        o += n;
      }
      int s = (e - o) * 2 - n;
      if (s > best) {
        best = s;
        bi = i;
      }

      if (i & 1) {
        e += n;
      }
    }
    result += o;
    // debug(bi);
    T.erase(T.begin() + bi);
  }
  cout << result;
}
#endif