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

// 2回2分探索をしても良いことを、証明したいね。意味としてはなんとなく分かるけど。
// 2回2分探索できそうでできない例：AOJ542
// ちょっと気まぐれだが、O(N^2logN)の枝刈りで通してみたくなったからそれで通す。→無理でした。
#include <iostream>
#include <stdio.h>
using namespace std;

#define GOMAE (long long)50000
#define EPS (long long)4000
#define TO_OUTSIDE (long long)1500
#define IS_NOT_EVEN_HOBBY (long long)573
int N;
long long input;
long long A[300010];
long long ans;

// A[medi]-A[st] >= A[ed]-A[medi]となる最小のmediを返す。
int seach1(int st, int ed) {
  int medi, s = st, e = ed;

  while (s <= e) {
    medi = (s + e) >> 1;
    if (A[medi] - A[st] == A[ed] - A[medi])
      break;
    if (A[medi] - A[st] > A[ed] - A[medi]) {
      if (A[medi - 1] - A[st] < A[ed] - A[medi - 1])
        break;
      e = medi - 1;
    } else {
      s = medi + 1;
    }
  }
  return medi;
}
// A[medi]-A[st] >= Xとなる最小のmediを返す。
int seach2(int st, int ed, long long X) {
  int s = st, e = ed, medi;
  while (s <= e) {
    medi = (s + e) >> 1;
    if (A[medi] - A[st] < X)
      s = medi + 1;
    if (A[medi] - A[st] >= X) {
      if (A[medi - 1] - A[st] < X)
        break;
      e = medi - 1;
    }
  }
  return medi;
}

int solve(long long X) {
  int i, j, k;

  if (X >= (A[N] >> 1))
    return 0;
  for (i = 0; i < N; i++) {
    // 大きさがX以上になるように切る
    j = seach2(i, N + i, X);
    // できるだけ真ん中で切る
    k = seach1(j, N + i);
    if (min(A[j] - A[i], min(A[k] - A[j], A[i + N] - A[k])) >= X)
      break;
    k--;
    if (min(A[j] - A[i], min(A[k] - A[j], A[i + N] - A[k])) >= X)
      break;
  }
  if (i < N)
    return 1;
  return 0;
}

int main() {
  int i, j, k;
  long long s = 0, e = GOMAE * EPS * TO_OUTSIDE * IS_NOT_EVEN_HOBBY * EPS;
  scanf("%d", &N);
  if (N > 100000)
    return 0;

  for (i = 1; i < N + 1; i++) {
    scanf("%d", &input);
    A[i] = A[i - 1] + input;
  }
  for (i = N + 1; i < 3 * N + 1; i++) {
    A[i] = A[i - N] + A[N];
  }

  // printf("%lld %lld\\n",s,e);
  while (s <= e) {
    ans = (s + e) >> 1;
    if (solve(ans)) {
      if (solve(ans + 1))
        s = ans + 1;
      else
        break;
    } else {
      e = ans - 1;
    }
  }
  printf("%lld\\n", ans);
  return 0;
}

Error: TLE

Fixed submission:

// 2回2分探索をしても良いことを、証明したいね。意味としてはなんとなく分かるけど。
// 2回2分探索できそうでできない例：AOJ542
// ちょっと気まぐれだが、O(N^2logN)の枝刈りで通してみたくなったからそれで通す。
#include <iostream>
#include <stdio.h>
using namespace std;

int N;
long long input;
long long A[300010];
long long ans;

// A[medi]-A[st] >= A[ed]-A[medi]となる最小のmediを返す。
int seach1(int st, int ed) {
  int medi, s = st, e = ed;

  while (s <= e) {
    medi = (s + e) >> 1;
    if (A[medi] - A[st] == A[ed] - A[medi])
      break;
    if (A[medi] - A[st] > A[ed] - A[medi]) {
      if (A[medi - 1] - A[st] < A[ed] - A[medi - 1])
        break;
      e = medi - 1;
    } else {
      s = medi + 1;
    }
  }
  return medi;
}
// A[medi]-A[st] > ansとなる最小のmediを返す。
int seach2(int st, int ed) {
  int s = st, e = ed, medi;
  while (s <= e) {
    medi = (s + e) >> 1;
    if (A[medi] - A[st] <= ans)
      s = medi + 1;
    if (A[medi] - A[st] > ans) {
      if (A[medi - 1] - A[st] <= ans)
        break;
      e = medi - 1;
    }
  }
  return medi;
}

int main() {
  int i, j, k;

  scanf("%d", &N);
  if (N > 100000)
    return 0;

  for (i = 1; i < N + 1; i++) {
    scanf("%d", &input);
    A[i] = A[i - 1] + input;
  }
  for (i = N + 1; i < 3 * N + 1; i++) {
    A[i] = A[i - N] + A[N];
  }

  for (i = 0; i < N; i++) {
    for (j = seach2(i, N); j < N; j++) {
      // できるだけ真ん中で切る
      k = seach1(j, i + N);
      ans = max(ans, min(A[j] - A[i], min(A[k] - A[j], A[i + N] - A[k])));
      k--;
      ans = max(ans, min(A[j] - A[i], min(A[k] - A[j], A[i + N] - A[k])));
    }
  }
  printf("%lld\\n", ans);
  return 0;
}