Cod sursa(job #3309051)

Utilizator pkseVlad Bondoc pkse Data 31 august 2025 15:22:44
Problema ADN Scor 100
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 4.7 kb
/*

    https://x.com/tigermcsr/status/1961877831358529714

*/
#include <bits/stdc++.h>
#define MOD 1000000007
#define B 127
using namespace std;

vector<int> powb(30005);

void bing() {
    powb[0] = 1;
    for(int i = 1; i <= 30000; i ++) {
        powb[i] = 1ll * powb[i - 1] * B % MOD;
    }
}

void imhashingit(string &s, vector<int> &hash) {
    hash.push_back(0);
    hash[0] = s[0];
    for(int i = 1; i < s.size(); i ++) {
        hash.push_back((1ll * hash[i - 1] * B % MOD + s[i]) % MOD);
    }
}

int whatsthehash(int st, int dr, vector<int> &hash) {
    if(st == 0)
        return hash[dr];
    st --;

    return (hash[dr] - (1ll * hash[st] * powb[dr - st] % MOD) + MOD) % MOD;
}

int findoverlap(vector<int> &hash1, vector<int> &hash2) {
    int n = hash1.size();
    int m = hash2.size();
    int st1 = n - min(n, m), dr1 = n - 1, st2 = 0, dr2 = min(n, m) - 1;
    for(; st2 <= dr2; st1 ++, dr2 --) {
        if(whatsthehash(st1, dr1, hash1) == whatsthehash(st2, dr2, hash2))
            return dr2 + 1;
    }
    return 0;
}

bool isstringinstring(vector<int> &hash1, vector<int> &hash2) {
    int n, m;
    n = hash1.size();
    m = hash2.size();
    if(n > m)
        return false;
    int st1 = 0, dr1 = n - 1;
    int st2 = 0, dr2 = n - 1;
    for(; dr2 < m; st2 ++, dr2 ++) {
        if(whatsthehash(st1, dr1, hash1) == whatsthehash(st2, dr2, hash2))
            return true;
    }
    return false;
}

int main() {
    freopen("adn.in", "r", stdin);
    freopen("adn.out", "w", stdout);
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n; cin >> n;

    vector<string> s(n);
    vector<vector<int>> hash(n);
    vector<vector<int>> overlap(n, vector<int>(n));

    bing();

    for(int i = 0; i < n; i ++) {
        cin >> s[i];
        imhashingit(s[i], hash[i]);
    }

    // cout << whatsthehash(0, s[0].size() - 1, hash[0]);
    // cout << whatsthehash(4, 15, hash[4]);

    for(int i = 0; i < n; i ++) {
        for(int j = 0; j < n; j ++) {
            if(i == j)
                continue;
            if(isstringinstring(hash[i], hash[j])) {
                s.erase(s.begin() + i);
                hash.erase(hash.begin() + i);
                i --;
                n --;
                break;
            }
        }
    }

    for(int i = 0; i < n; i ++) {
        for(int j = 0; j < n; j ++) {
            if(i == j)
                continue;
            overlap[i][j] = findoverlap(hash[i], hash[j]);
        }
    }

    // for(int i = 0; i < n; i ++) {
    //     for(int j = 0; j < n; j ++) {
    //         cout << overlap[i][j] << ' ';
    //     }
    //     cout << '\n';
    // }

    vector<vector<int>> dp((1 << n), vector<int>(n, 1e9));
    // vector<vector<vector<char>>> order((1 << n), vector<vector<char>>(n)); /// MLE on 1 test like fuck u, im gonna end it
    vector<vector<int>> last((1 << n), vector<int>(n, -1));

    for(int i = 0; i < n; i ++) {
        dp[(1 << i)][i] = s[i].size();
        // order[(1 << i)][i].push_back(i);
    }
    
    for(int mask = 1; mask < (1 << n); mask ++) {
        for(int i = 0; i < n; i ++) {
            if((mask & (1 << i)) == 0)
                continue;
            for(int j = 0; j < n; j ++) {
                if((mask & (1 << j)) != 0)
                    continue;
                // dp[mask ^ (1 << j)][j] = min(dp[mask ^ (1 << j)][j], dp[mask][i] + (int)s[j].size() - overlap[i][j]);
                if(dp[mask ^ (1 << j)][j] > dp[mask][i] + (int)s[j].size() - overlap[i][j]) {
                    dp[mask ^ (1 << j)][j] = dp[mask][i] + (int)s[j].size() - overlap[i][j];
                    last[mask ^ (1 << j)][j] = i;
                    // order[mask ^ (1 << j)][j] = order[mask][i];
                    // order[mask ^ (1 << j)][j].push_back(j);
                }
            }
        }
    }

    int ans = 1e9;

    vector<char> orderans;

    int anspos = -1;

    for(int i = 0; i < n; i ++) {
        // ans = min(ans, dp[(1 << n) - 1][i]);
        if(ans > dp[(1 << n) - 1][i]) {
            ans = dp[(1 << n) - 1][i];
            // orderans = order[(1 << n) - 1][i];
            anspos = i;
        }
    }

    // cout << *(s[0].begin() + 0);

    int mask = (1 << n) - 1;
    while(anspos>= 0) {
        orderans.push_back(anspos);
        int nwpos = last[mask][anspos];
        mask ^= (1 << anspos);
        anspos = nwpos;
    }

    reverse(orderans.begin(), orderans.end());
    
    cout << s[orderans[0]];
    for(int i = 1; i < n; i ++) {
        for(int j = overlap[orderans[i - 1]][orderans[i]]; j < s[orderans[i]].size(); j ++) {
            cout << s[orderans[i]][j];
        }
    }
}