Pagini recente » Cod sursa (job #947285) | Cod sursa (job #3338322) | Cod sursa (job #1914525) | Cod sursa (job #3312144) | Cod sursa (job #3327555)
#include <bits/stdc++.h>
#define ll long long
#define cin fin
#define cout fout
using namespace std;
ifstream fin("adn.in");
ofstream fout("adn.out");
const int NMAX = 18;
const int INF = 1e9;
const int BASE = 37;
const int MOD = 1e9 + 9;
const int SMAX = 3e4;
int n, answer, ind, start;
int x[NMAX + 1];
string answer_s;
string a[NMAX + 1];
string b[NMAX + 1];
int cost[NMAX + 1][NMAX + 1];
int prefix_hash[NMAX + 1][SMAX + 1];
int pbase[SMAX + 1];
int dp[1 << NMAX][NMAX + 1], parent[1 << NMAX][NMAX + 1];
int get_hash(int h[], int left, int right) {
return (h[right] - (ll) h[left - 1] * pbase[right - left + 1] % MOD + MOD) % MOD;
}
int get_cost(string& s1, string& s2) {
int r = s1.size() - 1, l = 0;
int hs1 = 0, hs2 = 0, pbase = 1, maxi = 0;
while(l < (int) s2.size() && r >= 0) {
hs1 = (hs1 + (ll) pbase * (s1[r] - 'A' + 1)) % MOD;
hs2 = ((ll) hs2 * BASE + (s2[l] - 'A' + 1)) % MOD;
l++;
r--;
pbase = (ll) pbase * BASE % MOD;
if(hs1 == hs2) {
maxi = l;
}
}
return s2.size() - maxi;
}
bool is_substring(int i, int j) {
int sz = a[i].size();
for(int pos = sz; pos <= a[j].size(); pos++) {
if(get_hash(prefix_hash[j], pos - sz + 1, pos) == prefix_hash[i][sz]) {
return true;
}
}
return false;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
pbase[0] = 1;
for(int i = 1; i <= SMAX; i++) {
pbase[i] = (ll) pbase[i - 1] * BASE % MOD;
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= a[i].size(); j++) {
prefix_hash[i][j] = ((ll) prefix_hash[i][j - 1] * BASE + (a[i][j - 1] - 'A' + 1)) % MOD;
}
}
for(int i = 1; i <= n; i++) {
bool ok = true;
for(int j = 1; j <= n; j++) {
if(i != j && is_substring(i, j)) {
ok = false;
}
}
if(ok) {
b[++ind] = a[i];
}
}
for(int i = 1; i <= ind; i++) {
a[i] = b[i];
}
n = ind;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) {
if(i != j) {
cost[i][j] = get_cost(a[i], a[j]);
}
}
}
for(int mask = 1; mask < (1 << n); mask++) {
for(int i = 1; i <= n; i++) {
dp[mask][i] = INF;
}
}
for(int i = 1; i <= n; i++) {
dp[1 << (i - 1)][i] = a[i].size();
}
for(int mask = 1; mask < (1 << n); mask++) {
for(int i = 1; i <= n; i++) {
if(mask >> (i - 1) & 1) {
for(int j = 1; j <= n; j++) {
if(i != j && (mask >> (j - 1) & 1)) {
int cost_here = dp[mask ^ (1 << (i - 1))][j] + cost[j][i];
if(cost_here < dp[mask][i]) {
dp[mask][i] = cost_here;
parent[mask][i] = j;
}
}
}
}
}
}
answer = INF;
for(int i = 1; i <= n; i++) {
if(dp[(1 << n) - 1][i] < answer) {
answer = dp[(1 << n) - 1][i];
start = i;
}
}
int mask = (1 << n) - 1;
while(start > 0) {
int j = parent[mask][start];
int stop = (j == 0 ? 0 : a[start].size() - cost[j][start]);
for(int i = a[start].size() - 1; i >= stop; i--) {
answer_s += a[start][i];
}
mask ^= (1 << (start - 1));
start = j;
}
reverse(answer_s.begin(), answer_s.end());
assert(answer_s.size() == answer);
cout << answer_s << '\n';
return 0;
}