HDU 4436 str2int (后缀自动机)

把所有的字符串连接起来,中间用一个未出现的字符分隔开,题意是求这个串的所有子串(中间不含分隔符)形成的数之和。

把这个串加入SAM,对所有子串进行拓扑排序,从前往后统计。

记录到达这个节点的路径个数cnt,以及到达这个节点的总和sum。

设父节点是u,子节点是v

sum[v] = sum[u] * 10 + sum[v] + cnt[v]*j;

cnt[v] += cnt[u];

ans就是把所有的sum加起来。

注意:

1.忽略前导零

2.子串中不要含分隔符

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <algorithm>



using namespace std;



const int MAXN = 100100;

const int segma_size = 14;

const int MOD = 2012;



struct Suffix_Automaton

{

    int F[MAXN << 1];               //fail

    int ant;                        //sum node

    int last;                       //last point

    int ch[MAXN << 1][segma_size];  //side

    int step[MAXN << 1];            //len



    void init()

    {

        last = ant = 1;

        memset(F,0,sizeof(F));

        memset(ch,0,sizeof(ch));

        memset(step,0,sizeof(step));

        return;

    }



    void ins( int x )

    {

        int t = ++ant, pa = last;

        step[t] = step[last] + 1;

        last = t;

        for( ; pa && !ch[pa][x]; pa = F[pa] )

            ch[pa][x] = t;

        if( pa == 0 ) F[t] = 1;

        else if( step[pa] + 1 == step[ ch[pa][x] ] )

            F[t] = ch[pa][x];

        else

        {

            int nq = ++ant, q = ch[pa][x];

            memcpy( ch[nq], ch[q], sizeof(ch[nq]) );

            step[nq] = step[pa] + 1;

            F[nq] = F[q];

            F[q] = F[t] = nq;

            for( ; pa && ch[pa][x] == q; pa = F[pa] )

                ch[pa][x] = nq;

        }

    }

};



int N;

char str[MAXN + 20];

int strL;

Suffix_Automaton SAM;

int r[MAXN << 1];

int sum[MAXN << 1];

int cnt[MAXN << 1];



bool cmp( int a, int b )

{

    return SAM.step[a] < SAM.step[b];

}



void show()

{

    for ( int i = 0; i <= SAM.ant; ++i )

    {

        for ( int j = 0; j < 10; ++j )

        {

            printf( "%d ", SAM.ch[i][j] );

        }

        puts("");

    }

    return;

}



int main()

{

    //freopen( "s.txt", "w", stdout );

    while ( scanf( "%d", &N ) == 1 )

    {

        SAM.init();

        strL = 0;

        for ( int n = 0; n < N; ++n )

        {

            if ( strL )

                str[strL++] = '9' + 1;

            scanf( "%s", &str[strL] );

            strL += strlen( &str[strL] );

        }

        for ( int i = 0; i < strL; ++i )

            SAM.ins( str[i] - '0' );



        for ( int i = 0; i <= SAM.ant; ++i )

            r[i] = i;



        sort( r + 1, r + 1 + SAM.ant, cmp );

        memset( sum, 0, sizeof(int)*(SAM.ant+4) );

        memset( cnt, 0, sizeof(int)*(SAM.ant+4) );



        int ans = 0;

        cnt[1] = 1;

        for ( int i = 1; i <= SAM.ant; ++i )

        {

            int u = r[i];

            if ( i > 1 && !cnt[u] ) continue;

            ans = ( ans + sum[u] ) % MOD;

            for ( int j = 0; j < 10; ++j )

            {

                if ( u == 1 && j == 0 ) continue;

                if ( !SAM.ch[u][j] ) continue;

                int v = SAM.ch[u][j];

                sum[v] = ( sum[u] * 10 + sum[v] + cnt[u] * j ) % MOD;

                cnt[v] += cnt[u];

            }

        }

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



    }

    return 0;

}

 

你可能感兴趣的:(int)