Cod sursa(job #2646472)

Utilizator DenisONIcBanu Denis Andrei DenisONIc Data 1 septembrie 2020 11:51:36
Problema ADN Scor 80
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 2.15 kb
#include <bits/stdc++.h>
using namespace std;

#define NMAX 20
#define LMAX 30004

int n, pr[LMAX], m[NMAX][NMAX], DP[(1<<18) + 10][20], ant[(1<<18) + 10][20];
string s[NMAX];

int kmpLast(string A, string B){
    swap(A,B);
    int k = 0;
    for (int i=2;i<A.size();i++){
        while (k && A[k+1] != A[i]) k = pr[k];
        if (A[i] == A[k+1]) k++;
        pr[i] = k;
    }

    k = 0;
    for (int i=1;i<B.size();i++){
        while (k && A[k+1] != B[i]) k = pr[k];
        if (B[i] == A[k+1]) k++;
        if (k+1 >= A.size()){
            return A.size();
        }
    }
    return k;
}

void reconst(int cfg, int lst){
    if(__builtin_popcount(cfg) == 1){
        cout << s[lst+1].substr(1);
        return;
    }

    int antLst = ant[cfg][lst];

    reconst(cfg ^ (1<<lst), antLst);

    for (int i=m[antLst+1][lst+1]+1;i<s[lst+1].size();i++) cout << s[lst+1][i];
}

int main()
{
    freopen("adn.in","r",stdin);
    freopen("adn.out","w",stdout);

    cin >> n;
    for (int i=1;i<=n;i++){
        cin >> s[i];
        s[i] = " " + s[i];
    }

    for (int tt=1;tt<=2;tt++)
    for (int i=1;i<=n;i++){
        for (int j=1;j<=n;j++){
            if (i==j) continue;

            m[i][j] = kmpLast(s[i], s[j]);
            if(m[i][j] == s[j].size()){
                s[j] = "";
            }
        }
    }

    int mx = 1<<n;

    memset(DP,0x3f,sizeof(DP));
    for (int i=1;i<mx;i++){
        for (int j=0;j<n;j++){
            if (!(i & (1<<j))) continue;
            if (__builtin_popcount(i) == 1){
                DP[i][j] = s[j+1].size();
            }
            for (int k=0;k<n;k++){
                if (i & (1<<k)) continue;

                int newV = DP[i][j] + s[k+1].size() - m[j+1][k+1];
                if (DP[i ^ (1<<k)][k] > newV){
                    DP[i ^ (1<<k)][k] = newV;
                    ant[i ^ (1<<k)][k] = j;
                }
            }
        }
    }

    int mn = 1e9, sav = -1;
    for (int i=0;i<n;i++){
        if (DP[mx-1][i] < mn){
            mn = DP[mx-1][i];
            sav = i;
        }
    }

    reconst(mx-1, sav);

    return 0;
}