Cod sursa(job #3338940)

Utilizator parus_majorParus Major parus_major Data 5 februarie 2026 15:22:56
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.2 kb
#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>
#include <climits>

using namespace std;

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

const int MAXL = 30002;
const int MAXN = 19;

int cost[MAXN][MAXN];
int phi[MAXL];
string s[MAXN];
bool included[MAXN];
int N, mask_included;
int dp[1 << MAXN][MAXN], prev_dp[1 << MAXN][MAXN];
vector<int> order;

int main()
{
    fin >> N;
    for (int i = 0; i < N; ++i) {
        fin >> s[i];
    }

    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < N; ++j) {
            if (i == j) continue;
            const auto& a = s[i];
            const auto& b = s[j];

            int k = 0;
            phi[1] = 0;
            for (int t = 1; t < b.length(); ++t) {
                while (k && b[k] != b[t]) k = phi[k];

                if (b[k] == b[t]) {
                    ++k;
                }
                phi[t + 1] = k;
            }

            k = 0;
            for (int t = 0; t < a.length(); ++t) {
                while (k && b[k] != a[t]) k = phi[k];
                if (b[k] == a[t]) ++k;
                if (k == b.length()) {
                    included[j] = true;
                    k = phi[k];
                }
            }
            cost[i][j] = b.length() - k;
        }
    }

    for (int i = 0; i < N; ++i) {
        if (included[i]) mask_included |= 1 << i;
    }
    // In case all sequences are equal.
    if (mask_included == (1 << N) - 1) {
        --mask_included;
    }

    for (int mask = 0; mask < (1 << N); ++mask) {
        for (int i = 0; i < N; ++i) {
            dp[mask][i] = INT_MAX / 2;
        }
    }
    for (int i = 0; i < N; ++i) {
        if (!included[i]) dp[1 << i][i] = s[i].length();
    }

    for (int mask = 0; mask < (1 << N); ++mask) {
        if (mask & mask_included) continue;
        if ((mask & (-mask)) == mask) continue;

        for (int last = 0; last < N; ++last) {
            if (!(mask & (1 << last))) continue;

            for (int prev = 0; prev < N; ++prev) {
                if (!(mask & (1 << prev))) continue;
                if (prev == last) continue;

                if (dp[mask][last] > dp[mask - (1 << last)][prev] + cost[prev][last]) {
                    dp[mask][last] = dp[mask - (1 << last)][prev] + cost[prev][last];
                    prev_dp[mask][last] = prev;
                }
            }
        }
    }

    int desired_mask = (1 << N) - 1 - mask_included;
    int start = 0;
    for (int i = 0; i < N; ++i) {
        if (dp[desired_mask][i] < dp[desired_mask][start]) {
            start = i;
        }
    }

    while (desired_mask) {
        order.push_back(start);
        const int prev = prev_dp[desired_mask][start];
        desired_mask -= 1 << start;
        start = prev;
    }
    reverse(order.begin(), order.end());
    
    std::string result = s[order[0]];
    for (int i = 1; i < order.size(); ++i) {
        const string& a = s[order[i]];
        const int& c = cost[order[i - 1]][order[i]];
        for (int j = a.length() - c; j < a.length(); ++j) {
            result.push_back(a[j]);
        }
    }

    fout << result;

    return 0;
}