Cod sursa(job #2787227)

Utilizator bogdanvladmihaiBogdan Vlad-Mihai bogdanvladmihai Data 22 octombrie 2021 18:53:07
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.13 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)1e7;
const int maxN = 18;
const int maxL = 30005;

int n;

char s[maxN][maxL + 2];

int lps[2 * maxL + 2];

int cost[maxN][maxN];

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

bool uniq[maxN];

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

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;
  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;
    }
  }
  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) {
      uniq[x] = false;
    }
  }
  return k;
}

vector<int> gen(pi curr) {
  if (curr.first == -1) {
    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);
    uniq[i] = true;
  }
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < n; j++) {
      if (i != j) {
        cost[i][j] = lgp(j, i);
      }
    }
  }
  vector<int> validNodes;
  for (int i = 0; i < n; i++) {
    if (uniq[i]) {
      validNodes.pb(i);
    }
  }
  for (int mask = 0; mask < (1 << n); mask++) {
    for (int i = 0; i < n; i++) {
      dp[mask][i] = -inf;
    }
  }
  for (int i = 0; i < n; i++) {
    if (uniq[i]) {
      dp[(1 << i)][i] = 0;
      prv[(1 << i)][i] = mp(-1, 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);
    }
  }
  for (int mask : validMasks) {
    for (int u : validNodes) {
      for (int v : validNodes) {
        if (u != v && (mask & (1 << v)) && (mask & (1 << u))) {
          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, cnt = n;
  for (int i = 0; i < n; i++) {
    if (!uniq[i]) {
      all ^= (1 << i);
      cnt--;
    }
  }
  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;
}