• HDU 4622 多校第三场1002 后缀自动机


    比赛的时候我是用后缀数组的,但是T了。

    赛后看了解题报告说,后缀数组貌似是卡你常数的时间,我算了下复杂度O(T * Q * n)。这是10 ^ 8,但是考虑到每次询问的时候都要重新构造字符,所以那个n可能是(3 - 4 ) * n,卡的可能就是这个常数。然后就过不了了。

    我先上一发我的后缀数组的代码,T的好惨。

    因为当时不会后缀自动机。

    #include<iostream>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include <cstdio>
    using namespace std;
    const int N=2005;
    /****后缀数组模版****/
    #define F(x)((x)/3+((x)%3==1?0:tb)) //F(x)求出原字符串的suffix(x)在新的字符串中的起始位置
    #define G(x)((x)<tb?(x)*3+1:((x)-tb)*3+2) //G(x)是计算新字符串的suffix(x)在原字符串中的位置,和F(x)为互逆运算
    int wa[N],wb[N],wv[N],WS[N];
    int sa[N*3] ;
    int rank1[N],height[N];
    int r[N*3];
    
    int c0(int *r,int a,int b) {
        return r[a]==r[b] && r[a+1]==r[b+1] && r[a+2]==r[b+2];
    }
    int c12(int k,int *r,int a,int b) {
        if(k==2)
            return r[a]<r[b] || ( r[a]==r[b] && c12(1,r,a+1,b+1) );
        else
            return r[a]<r[b] || ( r[a]==r[b] && wv[a+1]<wv[b+1] );
    }
    void sort(int *r,int *a,int *b,int n,int m) {
        int i;
        for(i=0; i<n; i++)
            wv[i]=r[a[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--)
            b[--WS[wv[i]]]=a[i];
        return;
    }
    
    //注意点:为了方便下面的递归处理,r数组和sa数组的大小都要是3*n
    void dc3(int *r,int *sa,int n,int m) { //rn数组保存的是递归处理的新字符串,san数组是新字符串的sa
        int i , j , *rn = r+n , *san = sa+n , ta = 0 ,tb = (n+1)/3 , tbc = 0 , p;
        r[n] = r[n+1] = 0;
        for(i=0; i<n; i++) {
            if(i%3!=0)
                wa[tbc++]=i; //tbc表示起始位置模3为1或2的后缀个数
        }
        sort(r+2,wa,wb,tbc,m);
        sort(r+1,wb,wa,tbc,m);
        sort(r,wa,wb,tbc,m);
        for(p=1,rn[F(wb[0])]=0,i=1; i<tbc; i++)
            rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;
        if(p<tbc)
            dc3(rn,san,tbc,p);
        else {
            for(i=0; i<tbc; i++)
                san[rn[i]]=i;
        }
    //对所有起始位置模3等于0的后缀排序
        for(i=0; i<tbc; i++) {
            if(san[i]<tb)
                wb[ta++]=san[i]*3;
        }
        if(n%3==1)  //n%3==1,要特殊处理suffix(n-1)
            wb[ta++]=n-1;
        sort(r,wb,wa,ta,m);
        for(i=0; i<tbc; i++)
            wv[wb[i]=G(san[i])]=i;
    //合并所有后缀的排序结果,保存在sa数组中
        for(i=0,j=0,p=0; i<ta&&j<tbc; p++)
            sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];
        for(; i<ta; p++)
            sa[p]=wa[i++];
        for(; j<tbc; p++)
            sa[p]=wb[j++];
        return;
    }
    
    //height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀
    void calheight(int *r,int *sa,int n) {
        int i,j,k=0;
        for(i=1; i<=n; i++)
            rank1[sa[i]]=i;
        for(i=0; i<n; height[rank1[i++]]=k)
            for(k?k--:0,j=sa[rank1[i]-1]; r[i+k]==r[j+k]; k++);
    }
    int solve(int n) {
        int i,sum=0;
        for(i=1; i<=n; i++) {
            sum += n - sa[i] - height[i] ;
        }
    
        return sum;
    }
    /****以上模版****/
    char now[2005] ;
    char str[N];
    inline void RD(int &ret) {
        char c;
        do {
            c = getchar();
        } while(c < '0' || c > '9') ;
        ret = c - '0';
        while((c=getchar()) >= '0' && c <= '9')
            ret = ret * 10 + ( c - '0' );
    }
    inline void OT(int a) {
        if(a >= 10)OT(a / 10) ;
        putchar(a % 10 + '0') ;
    }
    struct QU {
        int s ,e ,id ;
    } QQ[10005] ;
    bool cmp(QU a ,QU b) {
        if(a.s == b.s)return a.e < b.e ;
        return a.s < b.s ;
    }
    int ans[11111] ;
    int main() {
        int i,n,t;
        scanf("%d",&t);
        while(t--) {
            scanf("%s",str);
            memset(ans , 0 , sizeof(ans));
            int xd ;
            cin >> xd ;
            for (int i = 0 ; i < xd ; i ++ ) {
                RD(QQ[i].s) ;
                RD(QQ[i].e) ;
                QQ[i].s -- ;
                QQ[i].e -- ;
                QQ[i].id = i ;
            }
            sort(QQ , QQ + xd , cmp) ;
            int st = QQ[0].s ;
            int ed = QQ[0].e ;
            int num = 0 ;
            for (int i = st ; i <= ed ; i ++ )r[num ++] = (int)str[i] ;
            r[num] = 0 ;
            dc3(r , sa ,num + 1 , 200) ;
            calheight(r , sa, num ) ;
            ans[QQ[0].id] = solve(num) ;
            for (int i = 1 ; i < xd ; i ++ ) {
                if(QQ[i].s != QQ[i - 1].s) {
                    num = 0 ;
                    for (int j = QQ[i].s ; j <= QQ[i].e ; j ++ )r[num ++] = (int)str[j] ;
                    r[num] = 0 ;
                    dc3(r , sa , num + 1 ,200 ) ;
                    calheight(r ,sa ,num) ;
                    ans[QQ[i].id] = solve(num) ;
                    ed = QQ[i].e ;
                } else {
                    if(QQ[i].e == QQ[i - 1].e) {
                        ans[QQ[i].id] = ans[QQ[i - 1].id] ;
                    } else {
                        for (int j = ed + 1 ; j <= QQ[i].e ; j ++)r[num ++] = (int)str[j] ;
                        r[num] = 0 ;
                        dc3(r ,sa ,num + 1 , 200) ;
                        calheight(r ,sa ,num) ;
                        ans[QQ[i].id] = solve(num) ;
                        ed = QQ[i].e ;
                    }
                }
            }
            for (int i = 0 ; i < xd ; i ++ ) {
                OT(ans[i]) ;
                puts("") ;
            }
        }
        return 0;
    }
    


    昨天晚上和今天一直在看后缀自动机,这里推荐一个我看的懂的博客。

    http://blog.sina.com.cn/s/blog_70811e1a01014dkz.html

    算是学会了使用模版。当然也仅限于模版题。。好水。。继续学习。。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <string>
    #include <cmath>
    #include <cstring>
    #include <queue>
    #include <set>
    #include <vector>
    #include <stack>
    #include <map>
    #include <iomanip>
    #define PI acos(-1.0)
    #define Max 2505
    #define inf 1<<28
    #define LL(x) ( x << 1 )
    #define RR(x) ( x << 1 | 1 )
    #define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i )
    #define ll long long
    #define mem(a,b) memset(a,b,sizeof(a))
    #define mp(a,b) make_pair(a,b)
    #define PII pair<int,int>
    using namespace std;
    
    inline void RD(int &ret) {
        char c;
        do {
            c = getchar();
        } while(c < '0' || c > '9') ;
        ret = c - '0';
        while((c=getchar()) >= '0' && c <= '9')
            ret = ret * 10 + ( c - '0' );
    }
    inline void OT(int a){
        if(a >= 10)OT(a / 10) ;
        putchar(a % 10 + '0') ;
    }
    struct SAM {
        SAM*pre ,*next[26] ;
        int val ;
        void clear() {
            pre = 0 ;
            val = 0 ;
            mem(next ,0) ;
        }
    } ;
    SAM *root ,*last  ,*cur ;
    SAM qe[111111] ;
    int cnt = 0 ;
    void init() {
        cnt = 0 ;
        root = last = &qe[cnt ++] ;
        root -> clear() ;
    }
    struct QU{
        int s ,e ,id ;
    }QQ[100005] ;
    void extend(int w ) {
        SAM*p = last ;
        SAM*np = &qe[cnt ++] ;
        np -> clear() ;
        np -> val = p -> val + 1 ;
        while(p && !p -> next[w] )p -> next[w] = np ,p = p -> pre ;
        if(!p) {
            np -> pre = root ;
        } else {
            SAM *q = p -> next[w] ;
            if(p -> val + 1 == q -> val) {
                np -> pre = q ;
            } else {
                SAM *nq =  &qe[cnt ++] ;
                nq -> clear() ;
                memcpy(nq -> next ,q -> next ,sizeof(q -> next)) ;
    
                nq -> val = p -> val + 1 ;
                nq -> pre = q -> pre ;
                q -> pre = nq ;
                np -> pre = nq ;
                while(p && p -> next[w] == q) {
                    p -> next[w] = nq ;
                    p = p -> pre ;
                }
            }
        }
        last = np ;
    }
    
    #define N 100005
    #define M 2005
    char a[M] ;
    bool cmp(QU a ,QU b){
        if(a.s == b.s)return a.e < b.e ;
        return a.s < b.s ;
    }
    int solve(){
        int sum = 0 ;
        for (int i = cnt - 1 ; i > 0 ; i -- ){
            sum += qe[i].val - qe[i].pre -> val ;
        }
        return sum ;
    }
    int ans[N] ;
    int main() {
        int T ;
        cin >> T ;
        while( T -- ) {
            cin >> a ;
            mem(ans, 0) ;
            int l = strlen(a) ;
            int Q ;
            cin >> Q ;
            for (int i = 0 ; i < Q ; i ++ ){
                RD(QQ[i].s) ;
                RD(QQ[i].e) ;
                QQ[i].s -- ;
                QQ[i].e -- ;
                QQ[i].id = i ;
            }
            sort(QQ , QQ + Q , cmp) ;
            init() ;
            int st = QQ[0].s ;
            int ed = QQ[0].e ;
            for (int i = st ; i <= ed ; i ++ ){
                extend(a[i] - 'a') ;
            }
            for (int i = cnt - 1 ; i > 0 ; i -- ){
                ans[QQ[0].id] += qe[i].val - qe[i].pre -> val ;
            }
            for (int i = 1 ; i < Q ;i ++ ){
    //            cout << QQ[i].s << " " << QQ[i].e << endl;
    //            getchar() ;
                if(QQ[i].s != QQ[i - 1].s){
                    init() ;
                    for (int j = QQ[i].s ; j <= QQ[i].e ; j ++ )extend(a[j] - 'a' ) ;
                    ans[QQ[i].id] = solve() ;
                }
                else {
                    if(QQ[i].e == QQ[i - 1].e){
                        ans[QQ[i].id] = ans[QQ[i - 1].id] ;
                    }else{
                        for (int j = ed + 1 ; j <= QQ[i].e ; j ++ )extend(a[j] - 'a' ) ;
                        ans[QQ[i].id] = solve() ;
                    }
                }
                ed = QQ[i].e ;
            }
            for (int i = 0 ; i < Q ;i ++ ){
                OT(ans[i]) ;
                puts("") ;
            }
        }
        return 0 ;
    }
    


  • 相关阅读:
    vue中使用 canvas给页面添加水印
    c++ get keyboard event
    sublime text c++ makefile
    dddd
    songwenxin
    wechat
    ddd
    log
    v3
    xiaoxiaole
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3228760.html
Copyright © 2020-2023  润新知