Cod sursa(job #3255325)

Utilizator AlexandruBenescuAlexandru Benescu AlexandruBenescu Data 10 noiembrie 2024 12:53:33
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.93 kb
#include <bits/stdc++.h>
#define L 19
#define LL 30005
#define MASK_MAX (1 << L) + 5
#define BASE 27
#define MOD 1000000123
#define INVALID -1
#define INF 1000000001
using namespace std;
ifstream fin("adn.in");
ofstream fout("adn.out");

int n, ans, best;
string str[L], auxstr[L], v[L];
int h[L][LL], cost[L][L], invMod[LL];
pair <int, char> ham[MASK_MAX][L];
vector <int> path;
bool kick[L];

int qexp(int a, int b) {
  int p = 1;
  while (b) {
    if (b % 2 == 1)
      p = 1LL * p * a % MOD;
    a = 1LL * a * a % MOD;
    b /= 2;
  }
  return p;
}

void buildInvMod() {
  int p = 1;
  invMod[0] = 1;
  for (int i = 1; i < LL; i++) {
    p = 1LL * p * BASE % MOD;
    invMod[i] = qexp(p, MOD - 2);
  }
}

int getHash(int word, int l, int r) {
  return 1LL * (h[word][r] - h[word][l - 1] + MOD) * invMod[l - 1] % MOD;
}

void generateHam() {
  n++;
  for (int mask = 0; mask < (1 << n); mask++)
    for (int node = 0; node < n; node++)
      ham[mask][node] = {INVALID, INVALID};
  ham[1][0] = {0, INVALID};
  for (int mask = 1; mask < (1 << n); mask++)
    for (int node = 1; node < n; node++) {
      if ((mask & (1 << node)) || ham[mask | (1 << node)][node].first != INVALID)
        continue;
      ham[mask | (1 << node)][node] = {INF, INVALID};
      for (int i = 0; i < n; i++)
        if (ham[mask][i].first != INVALID && cost[i][node] != -1) {
          if (ham[mask | (1 << node)][node].first > ham[mask][i].first + cost[i][node])
            ham[mask | (1 << node)][node] = {ham[mask][i].first + cost[i][node], i};
        }
      if (ham[mask | (1 << node)][node].first == INF)
        ham[mask | (1 << node)][node] = {INVALID, INVALID};
    }

  ans = INF;
  best = -1;
  for (int node = 1; node < n; node++) {
    if (ham[(1 << n) - 1][node].first != INVALID) {
      if (ans > ham[(1 << n) - 1][node].first) {
        ans = ham[(1 << n) - 1][node].first;
        best = node;
      }
    }
  }
}

int main() {
  fin >> n;
  str[0] = "#X";
  for (int i = 1; i <= n; i++) {
    fin >> str[i];
    str[i] = "#" + str[i];
    for (int j = 1; j < (int)str[i].size(); j++)
      h[i][j] = (1LL * h[i][j - 1] + 1LL * (str[i][j] - 'A' + 1) * qexp(BASE, j)) % MOD;
  }

  buildInvMod();

  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      if (str[i].size() >= str[j].size())
        continue;
      bool out = false;
      for (int k = 1; k <= (int)str[j].size() - (int)str[i].size() + 1; k++)
        if (getHash(i, 1, str[i].size() - 1) == getHash(j, k, k + str[i].size() - 2))
          out = true;
      if (out)
        kick[i] = true;
    }
  }

  int ind = 1;
  for (int i = 1; i <= n; i++)
    if (!kick[i])
      auxstr[ind++] = str[i];
  n = ind - 1;

  for (int i = 1; i <= n; i++)
    str[i] = auxstr[i];

  for (int i = 1; i <= n; i++) {
    for (int j = 1; j < (int)str[i].size(); j++)
      h[i][j] = (1LL * h[i][j - 1] + 1LL * (str[i][j] - 'A' + 1) * qexp(BASE, j)) % MOD;
  }

  for (int i = 0; i <= n; i++) {
    for (int j = 0; j <= n; j++) {
      if (i == j) {
        cost[i][j] = -1;
        continue;
      }
      int c = str[j].size() - 1;
      for (int k = 0; k < (int)str[j].size(); k++) {
        if (str[i].size() - str[j].size() + k + 1 <= 0)
          continue;
        if (getHash(i, str[i].size() - str[j].size() + k + 1, str[i].size() - 1) == getHash(j, 1, str[j].size() - k - 1)) {
          c = k;
          break;
        }
      }
      cost[i][j] = c;
    }
  }

  generateHam();

  int node = best, mask = (1 << n) - 1;
  while (node != INVALID) {
    path.push_back(node);
    int aux = node;
    node = ham[mask][node].second;
    mask -= (1 << aux);
  }
  reverse(path.begin(), path.end());

  for (int i = 1; i < (int)path.size(); i++)
    for (int j = str[path[i]].size() - cost[path[i - 1]][path[i]]; j < (int)str[path[i]].size(); j++)
      fout << str[path[i]][j];
  fout << "\n";
  return 0;
}