Pagini recente » Cod sursa (job #3274049) | Cod sursa (job #3293102) | Cod sursa (job #2927477) | Cod sursa (job #143522) | Cod sursa (job #3247296)
#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;
}