Stunning Garbanzo
open main menu
Part of series: PS

1701 BOJ

/ 3 min read

문제

접근

KMP 알고리즘을 이용해 해결하였다.

부분문자열 중 두번 이상 나오는 가장 큰 것의 길이를 출력해야 한다. 두번 이상이라는 조건에 KMP의 pi 배열을 떠올렸는데, pi 배열은 맨 앞자리부터 시작하는 부분 배열만 검사하기 때문에 아닌 듯 싶었다. 시작 자리를 바꿔가면 pi 배열을 구할까 생각을 해봤는데 시간 초과가 염려되었다.

그래도 다른 방법이 생각나지 않아 위 방법으로 제출해봤는데, 아니나 다를까 시간초과가 떴다. 그래서 블로그들을 찾아 봤는데, 방법 자체가 틀린 것은 아니었다. 알고보니 pi 배열을 구하는 과정에서 오타를 냈었고, 해당 오타가 무한루프를 생성한 것이었다.

KMP는 아직도 어렵다 …

코드

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef const ll cll;
typedef queue<ll> qll;
typedef queue<pll> qpll;
typedef priority_queue<ll> pqll;
typedef priority_queue<pll> pqpll;
typedef vector<ll> vll;
typedef vector<pll> vpll;
typedef vector<vll> vvll;
typedef vector<vpll> vvpll;
#define FOR1(a, A) for (ll a = 0; a < A; ++a)
#define FOR2(a, b, A, B)                                                       \
  for (ll a = 0; a < A; ++a)                                                   \
    for (ll b = 0; b < B; ++b)
cll MAX_LEN = 5000;
string str;
ll pi[MAX_LEN + 1] = {};

int main(void) {
  ios::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);

  cin >> str;

  ll len = str.length(), result = 0;
  for (ll st = 0; st < len; ++st) {
    string subStr = str.substr(st);
    memset(pi, 0, sizeof(pi));
    for (ll _pi, i = 1; i < subStr.length(); ++i) {
      _pi = pi[i - 1];
      while (subStr[_pi] != subStr[i] && _pi) {
        _pi = pi[_pi - 1];
      }

      pi[i] = subStr[_pi] == subStr[i] ? _pi + 1 : 0;
      result = max(result, pi[i]);
    }
  }

  cout << result << "\n";

  return 0;
}