Cod sursa(job #3327554)

Utilizator BuzdiBuzdugan Rares Andrei Buzdi Data 4 decembrie 2025 14:54:17
Problema ADN Scor 40
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.89 kb
#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 = 2e9;
const int BASE = 37;
const int MOD = 1e9 + 9;
const int SMAX = 3e4;

int n, answer, ind;
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 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 i = 1; i <= n; i++) {
        x[i] = i;
    }
    answer = INF;
    do {
        int cost_here = a[x[1]].size();
        string here = a[x[1]];
        for(int i = 2; i <= n; i++) {
            cost_here += cost[x[i - 1]][x[i]];

            int pos_start = a[x[i]].size() - cost[x[i - 1]][x[i]];
            here += a[x[i]].substr(pos_start, cost[x[i - 1]][x[i]]);
        }
        if(cost_here < answer) {
            answer = cost_here;
            answer_s = here;
        }
    }while(next_permutation(x + 1, x + n + 1));
    cout << answer_s << '\n';
    return 0;
}