Cod sursa(job #3346034)

Utilizator eric.mesterEric Mestereaga eric.mester Data 12 martie 2026 10:44:07
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 3.26 kb
#include <bits/stdc++.h>
#define NMAX 20
#define MMAX 524288 ///2^18
#define INF INT_MAX
using namespace std;

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

int N;
string s[NMAX];
string s1[NMAX];
char elm[NMAX];
int c[NMAX][NMAX];
int dp[MMAX][NMAX];
pair<int,int> from[MMAX][NMAX];
string ans;

int get_cost(const string &a, const string &b)
{///cat costa sa lipim b de a (([a...][b...]))
    string s = b + "#" + a;
    int pi[s.length() + 2] = {0};
    pi[0] = 0;
    for(int i=1;i<s.length();i++){
        int j = pi[i-1];
        while(j > 0 && s[i] != s[j]){
            j = pi[j-1];
        }
        if(s[i] == s[j]) j++;
        pi[i] = j;
    }
    return b.length() - pi[s.length() - 1];
}

bool is_inside(const string &a, const string &b)
{///is a inside b?
    string s = a + "#" + b;
    int pi[s.length() + 2] = {0};
    pi[0] = 0;
    for(int i=1;i<s.length();i++){
        int j = pi[i-1];
        while(j > 0 && s[i] != s[j]){
            j = pi[j-1];
        }
        if(s[i] == s[j]) j++;
        pi[i] = j;
    }
    for(int i=a.length();i<s.length();i++){
        if(pi[i] == a.length()) return 1;
    }
    return 0;
}

int main()
{
    fin >> N;
    for(int i=1;i<=N;i++){
        fin >> s1[i];
    }
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            if(i==j || elm[j]) continue;
            if(is_inside(s1[i],s1[j])){
                elm[i] = 1;
                break;
            }
        }
    }
    int aux = 0;
    for(int i=1;i<=N;i++){
        if(!elm[i]) s[++aux] = s1[i];
    }
    N = aux;
//    cout << N << "\n";
//    for(int i=1;i<=N;i++){
//        cout  << s[i] << "\n";
//    }
    for(int i=1;i<=N;i++){
        for(int j=1;j<=N;j++){
            if(i==j) continue;
            c[i][j] = get_cost(s[i], s[j]);
        }
    }
    for(int mask = 1;mask < (1 << N);mask++){
        for(int node = 1;node <=N;node++){///creca as putea ceva smecherie cu lsb, da mai vedem
            if((mask & (1<<(node-1))) == 0) continue;
            if(__builtin_popcount(mask) == 1){
                dp[mask][node] = s[node].length();
                break;
            }
            dp[mask][node] = INF;
            for(int x = 1;x<=N;x++){
                if((mask & (1<<(x-1))) == 0 || node == x) continue;
                ///adaugam node dp[mask fara node][x]
                int len = dp[mask ^ (1<<(node-1))][x] + c[x][node];
                if(len < dp[mask][node]){
                    from[mask][node] = {mask ^ (1<<(node-1)), x};///nu mi trb neaparat si aia cu mask, da sybau
                    dp[mask][node] = len;
                }
            }
        }
    }
    pair <int,int> idx = {(1<<N) - 1, 1};
    for(int i=1;i<=N;i++){
        if(dp[(1<<N) - 1][i] < dp[idx.first][idx.second]){
            idx = {(1<<N) - 1, i};
        }
    }
    vector <int> indici;
    while(idx != pair<int,int>{0,0}){
        auto [i,j] = idx;
        indici.push_back(j);
        idx = from[i][j];
    }
    reverse(indici.begin(),indici.end());
    ans = s[indici[0]];
    for(int idx = 1;idx<indici.size();idx++){
        int i = indici[idx];
        int j = indici[idx-1];
        ///lipim s[i] la finalul lui s[j]
        int cost = c[j][i];
        for(int x = s[i].length() - cost; x< s[i].length(); x++){
            ans.push_back(s[i][x]);
        }
    }
    fout << ans;
}