Cod sursa(job #2787161)

Utilizator bogdanvladmihaiBogdan Vlad-Mihai bogdanvladmihai Data 22 octombrie 2021 17:43:44
Problema ADN Scor 30
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.47 kb
#include <bits/stdc++.h>

#define pi pair<int, int>
#define mp make_pair
#define pb push_back

using namespace std;

const int inf = (int)1e9;
const int maxN = 18;
const int maxL = (int)5e4;

int n;

char s[maxN][maxL + 2];

int lps[maxL + 2];

int cost[maxN][maxN];

int dp[(1 << maxN)][maxN];

bool uniq[maxN];

pi prv[(1 << maxN)][maxN];

bool included(int x, int y) {
  int n = (int)strlen(s[x] + 1), m = (int)strlen(s[y] + 1);
  memset(lps, 0, sizeof(lps));
  lps[0] = lps[1] = 0;
  for (int i = 2; i <= n; i++) {
    int k = lps[i - 1];
    while (k > 0 && s[x][k + 1] != s[x][i]) {
      k = lps[k];
    }
    if (s[x][k + 1] == s[x][i]) {
      lps[i] = k + 1;
    } else {
      lps[i] = 0;
    }
  }
  int k = 0;
  for (int i = 1; i <= m; i++) {
    while (k > 0 && s[x][k + 1] != s[y][i]) {
      k = lps[k];
    }
    if (s[x][k + 1] == s[y][i]) {
      k++;
      if (k == n) {
        return true;
      }
    } else {
      k = 0;
    }
  }
  return false;
}

int lgp(int x, int y) {
  int n = (int)strlen(s[x] + 1), m = (int)strlen(s[y] + 1);
  memset(lps, 0, sizeof(lps));
  lps[0] = lps[1] = 0;
  string v = "!";
  for (int i = 1; i <= n; i++) {
    v.pb(s[x][i]);
  }
  v += "?";
  for (int i = 1; i <= m; i++) {
    v.pb(s[y][i]);
  }
  int k = 0;
  for (int i = 2; i < (int)v.size(); i++) {
    while (k > 0 && v[k + 1] != v[i]) {
      k = lps[k];
    }
    if (v[k + 1] == v[i]) {
      k++;
    } else {
      k = 0;
    }
  }
  return k;
}

vector<int> gen(pi curr) {
  if (!curr.first) {
    return vector<int>{};
  }
  vector<int> result = gen(prv[curr.first][curr.second]);
  result.pb(curr.second);
  return result;
}

int main() {
  assert(freopen("adn.in", "r", stdin));
  assert(freopen("adn.out", "w", stdout));
  cin >> n;
  for (int i = 0; i < n; i++) {
    cin >> (s[i] + 1);
  }
  memset(uniq, true, sizeof(uniq));
  for (int i = 0; i < n; i++) {
    bool notIncluded = true;
    for (int j = 0; j < n; j++) {
      if (i != j && included(i, j) && uniq[j]) {
        notIncluded = false;
      }
    }
    uniq[i] = notIncluded;
  }
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      if (i != j) {
        cost[i][j] = lgp(j, i);
      }
    }
  }
  memset(dp, -inf, sizeof(dp));
  for (int i = 0; i < n; i++) {
    if (uniq[i]) {
      dp[(1 << i)][i] = 0;
    }
  }
  for (int mask = 0; mask < (1 << n); mask++) {
    for (int u = 0; u < n; u++) {
      if ((mask & (1 << u)) && uniq[u]) {
        for (int v = 0; v < n; v++) {
          if ((mask & (1 << v)) && uniq[v] && u != v) {
            int prevMask = mask ^ (1 << u);
            if (dp[mask][u] < dp[prevMask][v] + cost[v][u]) {
              dp[mask][u] = dp[prevMask][v] + cost[v][u];
              prv[mask][u] = mp(prevMask, v);
            }
          }
        }
      }
    }
  }
  int mx = -inf, start = -1;
  int all = (1 << n) - 1;
  for (int i = 0; i < n; i++) {
    if (!uniq[i]) {
      all ^= (1 << i);
    }
  }
  for (int i = 0; i < n; i++) {
    if (uniq[i] && mx < dp[all][i]) {
      mx = dp[all][i];
      start = i;
    }
  }
  vector<int> result = gen(mp(all, start));
  string str;
  for (int i = 0; i < (int)result.size(); i++) {
    if (i == 0) {
      int sz = (int)strlen(s[result[i]] + 1);
      for (int j = 1; j <= sz; j++) {
        str.pb(s[result[i]][j]);
      }
    } else {
      int sz = (int)strlen(s[result[i]] + 1);
      int c = cost[result[i - 1]][result[i]];
      for (int j = c + 1; j <= sz; j++) {
        str.pb(s[result[i]][j]);
      }
    }
  }
  cout << str << "\n";
  return 0;
}