Cod sursa(job #2787158)

Utilizator bogdanvladmihaiBogdan Vlad-Mihai bogdanvladmihai Data 22 octombrie 2021 17:38:57
Problema ADN Scor 20
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.68 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);
  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);
  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 && uniq[i] && uniq[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;
    }
  }
  vector<int> validMasks;
  for (int mask = 0; mask < (1 << n); mask++) {
    bool valid = true;
    for (int i = 0; i < n; i++) {
      if (!uniq[i] && (mask & (1 << i))) {
        valid = false;
      }
    }
    if (valid) {
      validMasks.pb(mask);
    }
  }
  vector<int> validNodes;
  for (int i = 0; i < n; i++) {
    if (uniq[i]) {
      validNodes.pb(i);
    }
  }
  for (int mask : validMasks) {
    for (int u : validNodes) {
      for (int v : validNodes) {
        if (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 - 1, 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;
}