Cod sursa(job #3154024)

Utilizator IvanAndreiIvan Andrei IvanAndrei Data 2 octombrie 2023 18:48:05
Problema ADN Scor 20
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.86 kb
#include <fstream>
#include <string>
#include <vector>

using namespace std;

ifstream in ("adn.in");
ofstream out ("adn.out");

const int max_conf = (1 << 20) + 5, max_size = 3e4 + 7, INF = 2e9 + 1;

string s[20];
int match[20][20], p[2 * max_size], nm[20], ans[20];
bool ok[20];
pair <int, int> dp[max_conf][19];
vector <int> conf[19];

bool kmp (int x, int y)
{
    string a = s[y] + '$' + s[x];
    int q = 0;
    for (int i = 1; i < a.size(); i++)
    {
        while (q > 0 && a[q] != a[i])
        {
            q = p[q - 1];
        }
        if (a[q] == a[i])
        {
            q++;
        }
        p[i] = q;
        if (p[i] == s[y].size())
        {
            return true;
        }
    }
    match[x][y] = s[y].size() - p[a.size() - 1];
    return false;
}

int preproc (int n)
{
    int x = 0;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if (i == j)
            {
                continue;
            }
            ok[j] |= kmp(i, j);
        }
    }
    for (int i = 0; i < n; i++)
    {
        if (!ok[i])
        {
            nm[x++] = i;
        }
    }
    return x;
}

int main ()
{
    int n;
    in >> n;
    for (int i = 0; i < n; i++)
    {
        in >> s[i];
    }
    n = preproc(n);
    for (int i = 0; i < (1 << n); i++)
    {
        conf[__builtin_popcount(i)].push_back(i);
    }
    for (int i = 0; i < n; i++)
    {
        dp[(1 << i)][i].first = s[nm[i]].size();
        dp[(1 << i)][i].second = -1;
    }
    for (int i = 2; i <= n; i++)
    {
        for (auto f : conf[i])
        {
            for (int j = 0; j < n; j++)
            {
                if ((f & (1 << j)) != 0)
                {
                    dp[f][j] = {INF, 0};
                    for (int k = 0; k < n; k++)
                    {
                        if (((f ^ (1 << j)) & (1 << k)) != 0)
                        {
                            dp[f][j] = min(dp[f][j], {dp[(f ^ (1 << j))][k].first + match[nm[k]][nm[j]], k});
                        }
                    }
                }
            }
        }
    }
    int ind = 0, mn = INF;
    for (int i = 0; i < n; i++)
    {
        if (dp[(1 << n) - 1][i].first < mn)
        {
            mn = dp[(1 << n)][i].first;
            ind = i;
        }
    }
    int mask = (1 << n) - 1, rez = 0;
    while (ind > -1)
    {
        ans[++rez] = ind;
        int aux = ind;
        ind = dp[mask][ind].second;
        mask ^= (1 << aux);
    }
    out << s[nm[ans[rez]]];
    for (int i = rez - 1; i > 0; i--)
    {
        int x = match[nm[ans[i + 1]]][nm[ans[i]]];
        for (int j = s[nm[ans[i]]].size() - x; j < s[nm[ans[i]]].size(); j++)
        {
            out << s[nm[ans[i]]][j];
        }
    }
    in.close();
    out.close();
    return 0;
}