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;
}

 

posted @ 2013-10-02 19:21  冰鸮  阅读(294)  评论(0编辑  收藏  举报