zoukankan      html  css  js  c++  java
  • 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
    ", ans );
    
        }
        return 0;
    }
  • 相关阅读:
    常用的汇编指令与技巧
    汇编调用c函数为什么要设置栈
    lp2356
    String函数的总结
    2019-5-22训练
    STL——substr
    STL 反转函数 (reverse() )
    2019-5-15训练——深搜
    高精度加法
    八皇后题解
  • 原文地址:https://www.cnblogs.com/GBRgbr/p/3349581.html
Copyright © 2011-2022 走看看