UVa 11475 Extend to Palindrome

長さ100000以下の文字列sが与えられる。sの後ろにできるだけ少ない文字列を連結して回文にし、出力せよ。

少し考えると、sをreverseした文字列をs_revとして

s.substr(s.size() - N) == s_rev.substr(0, N)

となるような最大のNを求めれば良い事が分かる(できるだけオーバーラップさせたいので)。
したがって、s_revをneedle、sをheystackとしてKMPを走らせて、終了時にPMAのどの状態にいるか調べれば良い。

#include <iostream>

using namespace std;

class KMP {
public:
  KMP(const string& pattern)
    : failure_(new int[pattern.size() + 1]), pattern_(pattern) {
    // build failure function
    failure_[0] = failure_[1] = 0;

    for (int i = 2; i <= pattern_.size(); ++i) {
      for (int j = failure_[i - 1]; ; j = failure_[j]) {
        if (pattern_[j] == pattern_[i - 1]) { failure_[i] = j + 1; break; }
        if (j == 0) { failure_[i] = 0; break; }
      }
    }
  }

  ~KMP() { delete[] failure_; }

  int Match(const string& text) {
    for (int i = 0, j = 0; ;) {
      if (j == text.size()) return i;

      if (text[j] == pattern_[i]) {
        ++i, ++j;
      } else if (i > 0) {
        i = failure_[i];
      } else {
        ++j;
      }
    }
  }

private:
  int *failure_;
  string pattern_;
};

int main() {
  string s;
  while (cin >> s) {
    string s_rev(s.rbegin(), s.rend());
    KMP kmp(s_rev);
    int max_match = kmp.Match(s);
    cout << (s + s_rev.substr(max_match)) << endl;
  }
}