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

#include <bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define SIZE 1000005
#define NUM1 1000000007
#define NUM2 99999883

struct Info {
  ull hash_1, hash_2;
};

int T_length;
char buf[SIZE], rev_buf[SIZE];
ull HASH[SIZE][2], rev_HASH[SIZE][2], POW[SIZE][2];

bool IS_SAME(Info left, Info right) {
  if (left.hash_1 == right.hash_1 && left.hash_2 == right.hash_2)
    return true;
  else {
    return false;
  }
}

Info calcHash(int left, int right) {

  Info ret;

  int length = right - left + 1;

  ret.hash_1 = HASH[right + 1][0] - HASH[left][0] * POW[length][0];
  ret.hash_2 = HASH[right + 1][1] - HASH[left][1] * POW[length][1];

  return ret;
}

Info rev_calcHash(int left, int right) {

  Info ret;

  int length = right - left + 1;

  ret.hash_1 = rev_HASH[right + 1][0] - rev_HASH[left][0] * POW[length][0];
  ret.hash_2 = rev_HASH[right + 1][1] - rev_HASH[left][1] * POW[length][1];

  return ret;
}

int main() {

  scanf("%d", &T_length);
  scanf("%s", buf);

  for (int i = T_length - 1; i >= 0; i--) {

    rev_buf[(T_length - 1) - i] = buf[i];
  }

  // 2通りのハッシュ値を計算する
  HASH[0][0] = 0;
  HASH[0][1] = 0;
  rev_HASH[0][0] = 0;
  rev_HASH[0][1] = 0;
  POW[0][0] = 1;
  POW[0][1] = 1;

  // ハッシュ値を求める
  for (int i = 1; i <= T_length; i++) {

    HASH[i][0] = buf[i - 1] + HASH[i - 1][0] * NUM1;
    HASH[i][1] = buf[i - 1] + HASH[i - 1][1] * NUM2;

    rev_HASH[i][0] = rev_buf[i - 1] + rev_HASH[i - 1][0] * NUM1;
    rev_HASH[i][1] = rev_buf[i - 1] + rev_HASH[i - 1][1] * NUM2;

    POW[i][0] = POW[i - 1][0] * NUM1;
    POW[i][1] = POW[i - 1][1] * NUM2;
  }

  bool FLG;

  int pre, length, mult, minus;
  int ans = -1, L, R;

  Info value, rev_value;

  for (int K = 2; K <= T_length; K++) {

    mult = 2;
    minus = 1;
    length = mult * K - minus;

    if (length > T_length) {

      pre = (length + 1) / 2;

      value = calcHash((pre - 1) - (T_length - pre), pre - 1);
      rev_value = rev_calcHash(0, T_length - pre);

      if (IS_SAME(value, rev_value)) {
        ans = K;
        break;
      }

    } else {

      pre = length;

      FLG = true;

      while (length <= T_length) {

        pre = length;

        // bufの先頭からlength文字が回文になっているか調べる
        L = 0;
        R = length - 1;

        value = calcHash(L, (length + 1) / 2 - 1);
        rev_value = rev_calcHash((T_length - 1 - R),
                                 (T_length - 1 - R - 1 + (length + 1) / 2));

        if (!IS_SAME(value, rev_value)) {
          FLG = false;
          break;
        }

        mult *= 2;
        minus = minus * 2 + 1;
        length = mult * K - minus;
      }

      if (!FLG)
        continue;

      if (pre == T_length) {
        ans = K;
        break;
      }

      // 残った部分が、回文の一部になっているか調べる
      L = 0;
      R = length - 1;

      value = calcHash((pre - 1) - (T_length - pre), pre - 1);
      rev_value = rev_calcHash(0, T_length - pre);

      if (IS_SAME(value, rev_value)) {
        ans = K;
        break;
      }
    }
  }

  printf("%d\\n", ans);

  return 0;
}


Error: TLE

Fixed submission:

#include <bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;

#define SIZE 1000005
#define NUM1 1000000007
#define NUM2 99999883

struct Info {
  ull hash_1, hash_2;
};

int T_length;
char buf[SIZE], rev_buf[SIZE];
ull HASH[SIZE][2], rev_HASH[SIZE][2], POW[SIZE][2];

bool IS_SAME(Info left, Info right) {
  if (left.hash_1 == right.hash_1 && left.hash_2 == right.hash_2)
    return true;
  else {
    return false;
  }
}

Info calcHash(int left, int right) {

  Info ret;

  int length = right - left + 1;

  ret.hash_1 = HASH[right + 1][0] - HASH[left][0] * POW[length][0];
  ret.hash_2 = HASH[right + 1][1] - HASH[left][1] * POW[length][1];

  return ret;
}

Info rev_calcHash(int left, int right) {

  Info ret;

  int length = right - left + 1;

  ret.hash_1 = rev_HASH[right + 1][0] - rev_HASH[left][0] * POW[length][0];
  ret.hash_2 = rev_HASH[right + 1][1] - rev_HASH[left][1] * POW[length][1];

  return ret;
}

int main() {

  scanf("%d", &T_length);
  scanf("%s", buf);

  for (int i = T_length - 1; i >= 0; i--) {

    rev_buf[(T_length - 1) - i] = buf[i];
  }

  // 2通りのハッシュ値を計算する
  HASH[0][0] = 0;
  HASH[0][1] = 0;
  rev_HASH[0][0] = 0;
  rev_HASH[0][1] = 0;
  POW[0][0] = 1;
  POW[0][1] = 1;

  // ハッシュ値を求める
  for (int i = 1; i <= T_length; i++) {

    HASH[i][0] = buf[i - 1] + HASH[i - 1][0] * NUM1;
    HASH[i][1] = buf[i - 1] + HASH[i - 1][1] * NUM2;

    rev_HASH[i][0] = rev_buf[i - 1] + rev_HASH[i - 1][0] * NUM1;
    rev_HASH[i][1] = rev_buf[i - 1] + rev_HASH[i - 1][1] * NUM2;

    POW[i][0] = POW[i - 1][0] * NUM1;
    POW[i][1] = POW[i - 1][1] * NUM2;
  }

  bool FLG;

  int pre, length, mult, minus;
  int ans = -1, L, R;

  Info value, rev_value;

  for (int K = 2; K <= T_length; K++) {

    mult = 2;
    minus = 1;
    length = mult * K - minus;
    pre = -1;

    FLG = true;

    while (length < T_length) {

      pre = length;

      // bufの先頭からlength文字が回文になっているか調べる
      L = 0;
      R = length - 1;

      value = calcHash(L, (length + 1) / 2 - 1);
      rev_value = rev_calcHash((T_length - 1 - R),
                               (T_length - 1 - R - 1 + (length + 1) / 2));

      if (!IS_SAME(value, rev_value)) {
        FLG = false;
        break;
      }

      mult *= 2;
      minus = minus * 2 + 1;
      length = mult * K - minus;
    }

    if (!FLG)
      continue;

    if (pre == T_length) {
      ans = K;
      break;
    }

    // 残った部分が、回文の一部になっているか調べる
    FLG = true;

    L = 0;
    R = length - 1;

    while (L < R) {
      if (R >= T_length) {
        R--;
        L++;
        continue;
      } else {
        if (buf[L] != buf[R]) {
          FLG = false;
          break;
        }
        L++;
        R--;
      }
    }

    if (FLG) {
      ans = K;
      break;
    }
  }

  printf("%d\\n", ans);

  return 0;
}