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

#include <algorithm>
#include <bitset>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
#define REP(i, j) for (int i = 0; i < (int)(j); ++i)
#define FOR(i, j, k) for (int i = (int)(j); i < (int)(k); ++i)
#define SORT(v) sort((v).begin(), (v).end())
#define REVERSE(v) reverse((v).begin(), (v).end())
typedef pair<int, string> P;
typedef unsigned long long ull;
const int INF = 1e9 + 7;
const int MAX_N = 14;

const ull B = 100000007;

// aはbに含まれているか
bool contain(string a, string b) {
  int al = a.length(), bl = b.length();
  if (al > bl)
    return false;

  ull t = 1;
  REP(i, al) t *= B;

  ull ah = 0, bh = 0;
  REP(i, al) ah = ah * B + a[i];
  REP(i, al) bh = bh * B + b[i];

  for (int i = 0; i + al <= bl; ++i) {
    if (ah == bh)
      return true; // bのi9文字目からのal文字が一致
    if (i + al < bl)
      bh = bh * B + b[i + al] - b[i] * t;
  }
  return false;
}

// aの末尾とbの先頭を何文字重ねることができるか
int overlap(string a, string b) {
  int al = a.length(), bl = b.length();
  int ans = 0;
  ull ah = 0, bh = 0, t = 1;
  for (int i = 1; i <= min(al, bl); ++i) {
    ah = ah + a[al - i] * t;
    bh = bh * B + b[i - 1];
    if (ah == bh)
      ans = i;
    t *= B;
  }
  return ans;
}

vector<string> make_ss(vector<string> &_ss, int N) {
  vector<string> res;
  REP(i, N) {
    bool f = true;
    REP(j, N) {
      if (i != j && contain(_ss[i], _ss[j]))
        f = false;
    }
    if (f)
      res.push_back(_ss[i]);
  }
  return res;
}

int main() {
  int N;
  while (cin >> N && N) {
    vector<string> _ss(N);
    REP(i, N) cin >> _ss[i];
    vector<string> ss = make_ss(_ss, N);
    N = ss.size();
    // REP(i, N) cout <<ss[i] <<", "; cout <<endl;
    int dp[(1 << MAX_N)][MAX_N];
    REP(i, (1 << MAX_N)) REP(j, N) dp[i][j] = INF;
    REP(i, N) dp[(1 << i)][i] = ss[i].length();
    int cost[MAX_N][MAX_N];
    REP(i, N)
    REP(j, N) cost[i][j] = (int)(ss[j].length()) - overlap(ss[i], ss[j]);
    // REP(i, N) REP(j, N) cout <<ss[i] <<", " <<ss[j] <<" = " <<cost[i][j]
    // <<endl;
    REP(i, (1 << MAX_N)) {
      REP(j, N) {
        if (dp[i][j] == INF)
          continue;
        // cout <<i <<", " <<dp[i][j] <<endl;
        REP(b, N) {
          if (i & (1 << b))
            continue;
          // cout <<i <<", " <<b <<", " <<(1 << b) <<", " <<(i | (1 << b)) <<",
          // " <<tmp <<", " <<(int)(tmp.length()) <<", " <<dp[i || (1 <<
          // b)].first <<endl;
          if (dp[i][j] + cost[j][b] < dp[i | (1 << b)][b])
            dp[i | (1 << b)][b] = dp[i][j] + cost[j][b];
        }
      }
    }
    int ans = INF;
    REP(i, N) ans = min(ans, dp[(1 << N) - 1][i]);
    cout << ans << endl;
  }
  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <bitset>
#include <cctype>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <iostream>
#include <limits>
#include <list>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
#define REP(i, j) for (int i = 0; i < (int)(j); ++i)
#define FOR(i, j, k) for (int i = (int)(j); i < (int)(k); ++i)
#define SORT(v) sort((v).begin(), (v).end())
#define REVERSE(v) reverse((v).begin(), (v).end())
typedef pair<int, string> P;
typedef unsigned long long ull;
const int INF = 1e9 + 7;
const int MAX_N = 14;

const ull B = 100000007;

// aはbに含まれているか
bool contain(string a, string b) {
  int al = a.length(), bl = b.length();
  if (al > bl)
    return false;

  ull t = 1;
  REP(i, al) t *= B;

  ull ah = 0, bh = 0;
  REP(i, al) ah = ah * B + a[i];
  REP(i, al) bh = bh * B + b[i];

  for (int i = 0; i + al <= bl; ++i) {
    if (ah == bh)
      return true; // bのi9文字目からのal文字が一致
    if (i + al < bl)
      bh = bh * B + b[i + al] - b[i] * t;
  }
  return false;
}

// aの末尾とbの先頭を何文字重ねることができるか
int overlap(string a, string b) {
  int al = a.length(), bl = b.length();
  int ans = 0;
  ull ah = 0, bh = 0, t = 1;
  for (int i = 1; i <= min(al, bl); ++i) {
    ah = ah + a[al - i] * t;
    bh = bh * B + b[i - 1];
    if (ah == bh)
      ans = i;
    t *= B;
  }
  return ans;
}

string check(string a, string b) {
  if (contain(b, a))
    return a;
  if (contain(a, b))
    return b;
  int abd = overlap(a, b);
  int bad = overlap(b, a);
  // cout <<"    " <<abd <<", " <<bad <<endl;
  if (abd == 0 && bad == 0)
    return a + b;
  if (abd > bad)
    return a + b.substr(abd);
  return b + a.substr(bad);
}

int main() {
  int N;
  while (cin >> N && N) {
    vector<string> ss(N);
    REP(i, N) cin >> ss[i];
    P dp[(1 << MAX_N)][MAX_N];
    REP(i, (1 << MAX_N)) REP(j, N) dp[i][j] = P(INF, "");
    REP(i, N) dp[(1 << i)][i] = P((int)(ss[i].length()), ss[i]);
    REP(i, (1 << MAX_N)) {
      REP(j, N) {
        if (dp[i][j].first == INF)
          continue;
        // cout <<i <<", " <<dp[i].second <<endl;
        REP(b, N) {
          if (i & (1 << b))
            continue;
          string tmp = check(dp[i][j].second, ss[b]);
          // cout <<i <<", " <<b <<", " <<(1 << b) <<", " <<(i | (1 << b)) <<",
          // " <<tmp <<", " <<(int)(tmp.length()) <<", " <<dp[i || (1 <<
          // b)].first <<endl;
          if ((int)(tmp.length()) < dp[i | (1 << b)][b].first)
            dp[i | (1 << b)][b] = P((int)(tmp.length()), tmp);
        }
      }
    }
    int ans = INF;
    REP(i, N) ans = min(ans, dp[(1 << N) - 1][i].first);
    cout << ans << endl;
  }
  return 0;
}