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

来源:互联网 发布:卖域名 赚钱么 编辑:程序博客网 时间:2024/06/07 05:24

比赛的时候我是用后缀数组的,但是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*nvoid 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 2005char 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 ;}


原创粉丝点击