• hdu4416 Good Article Good sentence (后缀数组)


    题意:求A 串中不在 所有B串中出现大不同子串的个数

    分析:后缀数组可以很简单的实现求一个串不同字子串的个数,,从这方面下手就很容易想到了,之前比赛的时候,,死活没想法

    先将所有串拼接起来,计算不包含分隔符的不同子串的个数sumAB,再单独将所有B串拼接起来,同样的方法求一遍,得到sumB,sumAB-sumB即为所求

    View Code
    #include <iostream>
    #include <algorithm>
    #include <string.h> 
    #include <math.h>
    #include <string>
    
    int const N= 400100;    
    int wa[N], wb[N], ws[N*2], wv[N];    
    int rank[N], sa[N], height[N], r[N];    
    char str[N];
    
    int cmp( int* r, int a, int b, int L ){    
        return r[a]== r[b] && r[a+ L]== r[b+ L];    
    }    
        
    void da( int* r, int* sa, int n, int m ){    
        int i, j, p, *x= wa, *y= wb, *t;    
        for( i= 0; i< m; ++i ) ws[i]= 0;    
        for( i= 0; i< n; ++i ) ws[ x[i]= r[i] ]++;    
        for( i= 1; i< m; ++i ) ws[i]+= ws[i-1];    
        for( i= n- 1; i>= 0; i-- ) sa[ --ws[ x[i] ] ]= i;    
        
        for( j= 1, p= 1; p< n; j*= 2, m= p ){    
            for( p= 0, i= n- j; i< n; ++i ) y[p++]= i;    
            for( i= 0; i< n; ++i )    
                if( sa[i]>= j ) y[p++]= sa[i]- j;    
        
            for( i= 0; i< n; ++i ) wv[i]= x[y[i]];    
            for( i= 0; i< m; ++i ) ws[i]= 0;    
            for( i= 0; i< n; ++i ) ws[ wv[i] ]++;    
            for( i= 1; i< m; ++i ) ws[i]+= ws[i-1];    
            for( i= n- 1; i>= 0; i-- ) sa[ --ws[ wv[i] ] ]= y[i];    
        
            t= x, x= y, y= t, p= 1; x[ sa[0] ]= 0;    
            for( i= 1; i< n; ++i )    
                x[ sa[i] ]= cmp( y, sa[i-1], sa[i], j )? p- 1: p++;    
        }    
    }    
        
    void callheight( int* r, int*sa, int n ){    
        int i, j, k= 0;    
        for( i= 1; i<= n; ++i ) rank[ sa[i] ]= i;    
        
        for( i= 0; i< n; height[ rank[i++] ]= k )    
            for( k?k--:0, j= sa[ rank[i]- 1]; r[i+k]== r[j+k]; k++ );    
        
    }
    
    int s[N],length[N],id[N];
    //s[]表示每一个串的在拼接后在串中的起始下标,length[]表示每一个串的长度,id[]记录拼接后每一个下标对应的原串的id
    __int64 get_num(int n)//计算不包含分隔符的不同子串的个数
    {
        __int64 sum=0;
        for(int i=1;i<=n;++i)
        {
            if(id[sa[i]]<0) continue;
            sum+=length[id[sa[i]]]-(sa[i]-s[id[sa[i]]])-height[i];
            //拼接后的串的计算子串的方法跟单个串的时候差不多,,原来是一样的,,只不过不能忽视分隔符的存在
        }
        return sum;
    }
    void print(int *s,int n)
    {
        for(int i=0;i<n;++i)
            printf("%d ",s[i]);
        printf("\n");
    }
    int main()
    {
        int T,cas=0;
        int n;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            memset(id,-1,sizeof(id));
            int len=-1,m=27;
            for(int i=0;i<=n;++i)
            {
                ++len;
                scanf("%s",str);
                length[i]=strlen(str);
                s[i]=len;
                for(int j=0;j<length[i];++j)
                {
                    id[len]=i;
                    r[len++]=str[j]-'a'+1;
                }
                r[len]=m++;
            }
            r[len]=0;
            da(r,sa,len+1,m);
            callheight(r,sa,len);
            __int64 ans1=get_num(len);//A串 + B 串中所有串可以形成的总的不同子串的个数
            for(int i=1;i<=n;++i)
                s[i]=s[i]-length[0]-1;
            for(int i=0;i<=len-length[0]-1;++i)
            {
                id[i]=id[i+length[0]+1];
                r[i]=r[i+length[0]+1];
            }
            len=len-length[0]-1;
            da(r,sa,len+1,m);
            callheight(r,sa,len);
            __int64 ans2=get_num(len);//B中所有串可以形成的总的子串的个数
            printf("Case %d: %I64d\n",++cas,ans1-ans2);
        }
        return 0;
    }
  • 相关阅读:
    ACM模板(Java)
    【HDU 6008】Worried School(模拟)
    【HDU 6005】Pandaland(Dijkstra)
    jQuery和js使用点滴
    springmvc入门(1)
    MyBatis延迟加载和缓存(4)
    MyBatis高级映射查询(3)
    教你如何下载微信公众号的音频文件
    MyBatis代理开发(2)
    MyBatis入门程序(1)
  • 原文地址:https://www.cnblogs.com/nanke/p/2714648.html
Copyright © 2020-2023  润新知