Cod sursa(job #3247296)

Utilizator IanisBelu Ianis Ianis Data 6 octombrie 2024 20:46:02
Problema ADN Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.65 kb
#pragma GCC optimize("Ofast,unroll-loops")
#include <bits/stdc++.h>

using namespace std;

#define fi first
#define se second

#define sz(a) int((a).size())
#define all(a) (a).begin(), (a).end()

#define lsb(x) (x & (-x)) 

#ifdef LOCAL
ifstream fin("input.txt");
#define fout cout
#else
ifstream fin("adn.in");
ofstream fout("adn.out");
#endif

template<typename T>
bool ckmax(T &a, T b) {
   return a < b ? a = b, true : false;
}
template<typename T>
bool ckmin(T &a, T b) {
   return a > b ? a = b, true : false;
}

using ll = long long;
using pii = pair<int, int>;

const int NMAX = 18;
const int INF = 1e9+5;
const int LMAX = 3e4+5;
const int A = 7;
const int MOD = 1e9+7;

struct State {
   int val = INF, next = -1, next_mask = -1;
   void comb(int _val, int _next, int _mask) {
      if (ckmin(val, _val)) {
         next = _next;
         next_mask = _mask;
      }
   }
};

int n, m;
char a[NMAX][LMAX];
int len[NMAX];
State dp[NMAX][1 << NMAX];
int cost[NMAX][NMAX];
int pref[NMAX][LMAX];
bool substr[NMAX][NMAX];
int inv[LMAX];
char val[128];

void read() {
   fin >> n;
   for (int i = 0; i < n; i++) {
      char *s = a[i] + 1;
      fin >> s;
      len[i] = strlen(a[i] + 1);
   }
}

int lgpow(int a, int n) {
   if (n == 0) return 1;
   if (n & 1) return 1ll * a * lgpow(a, n ^ 1) % MOD;
   int p = lgpow(a, n >> 1);
   return 1ll * p * p % MOD;
}

int hash_range(int x, int l, int r) {
   return 1ll * ((1ll * pref[x][r] - pref[x][l - 1] + MOD) % MOD) * inv[l - 1] % MOD;
}

int calc_cost(int x, int y) {
   for (int i = min(len[x], len[y]); i >= 1; i--) {
      if (hash_range(x, len[x] - i + 1, len[x]) == hash_range(y, 1, i))
         return i;
   }
   return 0;
}

bool is_substr(int x, int y) {
   if (len[x] < len[y]) return false;

   for (int i = 1; i <= len[x] - len[y] + 1; i++) {
      if (hash_range(x, i, i + len[y] - 1) == pref[y][len[y]])
         return true;
   }

   return false;
}

string build_ans(int x, int mask) {
   if (dp[x][mask].next == -1) {
      return string(a[x] + 1);
   }
   string s = build_ans(dp[x][mask].next, dp[x][mask].next_mask);
   if (x == dp[x][mask].next)
      return s;
   return s + string(a[x] + cost[dp[x][mask].next][x] + 1, a[x] + len[x] + 1);
}

string solve() {
   inv[0] = 1;
   inv[1] = lgpow(A, MOD - 2);
   for (int i = 2; i < LMAX; i++) {
      inv[i] = 1ll * inv[i - 1] * inv[1] % MOD;
   }

   val['A'] = 1;
   val['C'] = 2;
   val['G'] = 3;
   val['T'] = 4;
   for (int i = 0; i < n; i++) {
      int p = 1;
      for (int j = 1; a[i][j]; j++) {
         pref[i][j] = (1ll * pref[i][j - 1] + 1ll * val[int(a[i][j])] * p) % MOD;
         p = 1ll * p * A % MOD;
      }
   }

   for (int i = 0; i < n; i++) {
      for (int j = 0; j < n; j++) {
         if (i != j) {
            cost[i][j] = calc_cost(i, j);
            substr[i][j] = is_substr(i, j);
         } else {
            cost[i][j] = len[i];
            substr[i][j] = true;
         }
      }
   }

   for (int i = 0; i < n; i++) {
      dp[i][1 << i] = State { len[i], -1, -1 };
   }

   for (int mask = 0; mask < 1 << n; mask++) {
      for (int i = 0; i < n; i++) {
         if ((mask >> i) & 1) {
            for (int j = 0; j < n; j++) {
               if (!((mask >> j) & 1)) {
                  dp[j][mask | (1 << j)].comb(dp[i][mask].val + len[j] - cost[i][j], i, mask);
                  if (substr[i][j])
                     dp[i][mask | (1 << j)].comb(dp[i][mask].val, i, mask);
               }
            }
         }
      }
   }

   int ans = INF, x = -1, mask = (1 << n) - 1;
   for (int i = 0; i < n; i++) {
      if (ckmin(ans, dp[i][(1 << n) - 1].val))
         x = i;
   }

   return build_ans(x, mask);
}

signed main() {
   read();
   fout << solve() << endl;
   return 0;
}