Cod sursa(job #1572472)

Utilizator StarGold2Emanuel Nrx StarGold2 Data 18 ianuarie 2016 22:20:12
Problema Abc2 Scor 0
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.74 kb
#include <cstdio>
#include <algorithm>
#include <deque>
#include <vector>
#include <cstring>


const int SIGMA = 3;
using namespace std;

int NrWords, Answer, Vector[1 << 16];
char String[1 << 24], Word[1 << 16][1 << 6], NewWord[1 << 16][1 << 6];

class state_machine {
  private:

    struct tree {

        int cnt_words;
        int cnt_children;
        int cnt_occurrences;

        tree *children[SIGMA];
        tree *back_node;

        vector <tree *> front_node;

        tree () {

            cnt_words = NULL;
            back_node = NULL;
            cnt_children = NULL;
            cnt_occurrences = NULL;


            for( int i = 0; i < SIGMA; i ++ )
                children[i] = NULL;

            front_node.clear();
        }
    } *Root = new tree;

    void insert_word( tree *Node, char *String ) {

        if( *String == NULL ) {
            Node -> cnt_words ++;
            return;
        }

        if( Node -> children[*String - 'a'] == NULL ) {
            Node -> children[*String - 'a'] = new tree;
            Node -> cnt_children ++;
        }

        insert_word( Node -> children[*String - 'a'], String + 1 );
        return;
    }

    void build_back_edges( tree *start_node ) {

        deque <tree *> Queue;
        Queue.push_back(start_node);

        while( !Queue.empty() ) {
            tree *Node = Queue.front();

            for( int i = 0; i < SIGMA; i ++ ) {
                if( Node -> children[i] != NULL ) {
                    tree *Aux = Node -> back_node;

                    while( Aux && Aux -> children[i] == NULL )
                        Aux = Aux -> back_node;

                    if( Aux == NULL )
                        Node -> children[i] -> back_node = Root;
                    else
                        Node -> children[i] -> back_node = Aux -> children[i];

                    Node -> children[i] -> back_node -> front_node.push_back(Node -> children[i]);
                    Queue.push_back( Node -> children[i] );
                }
            }

            Queue.pop_front();
        }

        return;
    }

    void build_occurrences( tree *Node, char *String ) {

        if( *String == NULL )
            return;

        while( Node != Root && Node -> children[*String - 'a'] == NULL )
            Node = Node -> back_node;

        if( Node -> children[*String - 'a'] != NULL )
            Node = Node -> children[*String - 'a'];

        Node -> cnt_occurrences ++;
        build_occurrences( Node, String + 1 );

        return;
    }

    void build_partial_sum( tree *Node ) {

        for( int i = 0; i < Node -> front_node.size(); i ++ ) {
            build_partial_sum( Node -> front_node[i] );
            Node -> cnt_occurrences += Node -> front_node[i] -> cnt_occurrences;
        }

        return;
    }

    int count_occurrences( tree *Node, char *String ) {

        if( *String == NULL )
            return Node -> cnt_occurrences;

        if( Node -> children[*String - 'a'] != NULL )
            return count_occurrences( Node -> children[*String - 'a'], String + 1 );

        return 0;
    }

  public:

    void insert_word( char *String ) {
        insert_word( Root, String );
        return;
    }

    void build_occurrences( char *String ) {

        build_back_edges( Root );
        build_occurrences( Root, String );
        build_partial_sum( Root );

        return;
    }

    int count_occurrences( char *String ) {
        return count_occurrences( Root, String );
    }

} my_state_machine;

inline int CMP( int a, int b ) {
    for( int i = 0; Word[a][i] != 0; i ++ )
        if( Word[a][i] != Word[b][i] )
            return Word[a][i] < Word[b][i];
    return a < b;
}

inline int CMP2( int a, int b ) {
    for( int i = 0; NewWord[a][i] != 0; i ++ )
        if( NewWord[a][i] != NewWord[b][i] )
            return 0;
    return 1;
}

int main () {

    freopen( "abc2.in" , "r", stdin  );
    freopen( "abc2.out", "w", stdout );

    scanf( "%s", String );
    while( scanf( "%s", Word[++NrWords] )) {

        if( Word[NrWords][0] == NULL ) {
            NrWords --;
            break;
        }

        my_state_machine.insert_word( Word[NrWords] );
        Vector[NrWords] = NrWords;
    }

    my_state_machine.build_occurrences( String );
    sort( Vector + 1, Vector + NrWords + 1, CMP );

    for( int i = 1; i <= NrWords; i ++ )
        memcpy( NewWord[i], Word[Vector[i]], sizeof( Word[Vector[i]] ));

    for( int i = 1; i <= NrWords; i ++ ) {
        while( CMP2( i, i + 1 ) )
            i ++;
        Answer += my_state_machine.count_occurrences( NewWord[i] );
    }

    printf( "%d\n", Answer );

    return 0;
}