Cod sursa(job #2765202)

Utilizator DordeDorde Matei Dorde Data 25 iulie 2021 18:34:27
Problema ADN Scor 0
Compilator cpp-64 Status done
Runda Arhiva de probleme Marime 5.08 kb
#include <fstream>
#include <vector>
#include <algorithm>
#define mp make_pair

using namespace std;
int const N = 1 << 20 , M = 20 , m1 = 666013 , m2 = 1e9 + 7 , Lg = 30010 , inf = 1 << 29;
string S [100];
bool viz [M];
pair <int , int> hL [M][Lg] , hR [M][Lg] , t [N][M];
int R , C [M][M] , n , dp [N][M];
vector <int> v [M];
int value (char x){
    if (x == 'A')
        return 0;
    if (x == 'C')
        return 1;
    if (x == 'T')
        return 2;
    return 3;
}
void gethash (int line){
    hL [line][0] = mp (value (S [line][0]) , value (S [line][0]));
    for(int i = 1 ; i < (int)S [line].size () ; ++ i){
        int v1 = (4LL * hL [line][i - 1].first + value (S [line][i])) % m1;
        int v2 = (4LL * hL [line][i - 1].second + value (S [line][i])) % m2;
        hL [line][i] = mp (v1 , v2);
    }
    int sz = (int)S [line].size () - 1 , p1 = 4 , p2 = 4;
    hR [line][sz] = mp (value (S [line][sz]) , value (S [line][sz]));
    for(int i = sz - 1 ; i >= 0 ; -- i){
        int v1 = (1LL * hR [line][i + 1].first + 1LL * p1 * value (S [line][i])) % m1;
        int v2 = (1LL * hR [line][i + 1].second + 1LL * p2 * value (S [line][i])) % m2;
        hR [line][i] = mp (v1 , v2);
        p1 = 4LL * p1 % m1;
        p2 = 4LL * p2 % m2;
    }
    return;
}
int Delete (){
    string* S2 = new string [M];
    pair <int , int> **A  , **B;
    A = new pair <int , int>* [M];
    B = new pair <int , int>* [M];
    for(int i = 0 ; i < M ; ++ i){
        A [i] = new pair <int , int> [Lg];
        B [i] = new pair <int , int> [Lg];
    }
    int k = 0;
    for(int i = 0 ; i < n ; ++ i){
        if (viz [i]){
            R -= S [i].size ();
            continue;
        }
        S2 [k ++] = S [i];
        copy (hL [i] , hL [i] + S [i].size () , A [k - 1]);
        copy (hR [i] , hR [i] + S [i].size () , B [k - 1]);
    }
    for(int i = 0 ; i < k ; ++ i){
        copy (A [i], A [i]+ S2 [i].size () , hL [i]);
        copy (B [i], B [i]+ S2 [i].size () , hR [i]);
    }
    copy (S2 , S2 + k , S);
    delete S2;
    delete A;
    delete B;
    return k;
}
bool match (string A , string B , int x , int y){
    if (A.size () > B.size ())
        return false;
    pair <int , int> val = hL [x][A.size () - 1];
    pair <int , int> k = hL [y][A.size () - 1];
    if (val == k)
        return true;
    int p1 = 4 , p2 = 4;
    for(int i = 1 ; i < (int)A.size () ; ++ i){
        p1 = (4LL * p1) % m1;
        p2 = (4LL * p2) % m2;
    }
    for(int i = (int)A.size () ; i < (int)B.size () ; ++ i){
        int v1 = k.first , v2 = k.second;
        v1 = (4LL * v1 + value (B[i]) + 1LL * p1 * m1 - 1LL * p1 * value (B[i - A.size ()])) % m1;
        v2 = (4LL * v2 + value (B[i]) + 1LL * p2 * m2 - 1LL * p2 * value (B[i - A.size ()])) % m2;
        if ((k = mp (v1 , v2)) == val)
            return true;
    }
    return false;
}
int getEdge (int x , int y){
    int sz = S [x].size () - 1 , r = -1;
    for(int i = 0 ; i < min (int(S [x].size ()) , int(S [y].size ())) ; ++ i)
        if (hL [y][i] == hR [x][sz - i])
            r = i;
    return 1 + r;
}
ifstream f ("adn.in");
ofstream g ("adn.out");
int main()
{
    f >> n;
    for(int i = 0 ; i < n ; ++ i){
        f >> S [i];
        R += S [i].size ();
        gethash (i);
    }
    for(int i = 0 ; i < n ; ++ i)
        for(int j = 0 ; j < n ; ++ j){
            if (i == j)
                continue;
            if (match (S [i] , S [j] , i , j))
                viz [i] = true;
        }
    n = Delete ();
    for(int i = 0 ; i < n ; ++ i){
        for(int j = 0 ; j < n ; ++ j){
            if (i == j)
                continue;
            v[j].push_back (i);
            C [i][j] = getEdge (i , j);
        }
    }
    for(int i = 0 ; i < (1 << n) ; ++ i)
        for(int j = 0 ; j < n ; ++ j)
            dp [i][j] = -inf;
    for(int i = 0 ; i < n ; ++ i)
        dp [(1 << i)][i] = 0;
    for(int i = 1 ; i < (1 << n) ; ++ i)
        for(int j = 0 ; j < n ; ++ j)
            if ((1 << j) & i)
                for(int k = 0 ; k < (int)v [j].size () ; ++ k)
                    if ((1 << v [j][k]) & i){
                        if (dp [i][j] < dp [i ^ (1 << j)][v [j][k]] + C [v [j][k]][j]){
                            dp [i][j] = dp [i ^ (1 << j)][v [j][k]] + C [v [j][k]][j];
                            t [i][j] = mp (v [j][k] , j);
                        }
                    }
    int ans = -inf , ind = 0;
    vector <int> sol;
    for(int i = 0 ; i < n ; ++ i)
        if (dp [(1 << n) - 1][i] >= ans){
            ans = dp [(1 << n) - 1][i];
            ind = i;
        }
    int cfg = (1 << n) - 1;
    pair <int , int> x = t [cfg][ind];
    sol.push_back (ind);
    for(cfg ^= (1 << x.second); cfg ; cfg ^= (1 << x.second)){
        ind = x.first;
        sol.push_back (ind);
        x = t [cfg][ind];
    }
    reverse (sol.begin () , sol.end ());
    g << S [sol [0]];
    for(int i = 1 ; i < n ; ++ i){
        for(int j = C [sol [i - 1]][sol [i]] ; j < (int)S [sol [i]].size () ; ++ j)
            g << S [sol [i]][j];
    }
    return 0;
}