HDU3948:后缀数组+马拉车(本质不同回文子串统计)

来源:互联网 发布:php部署到apache 编辑:程序博客网 时间:2024/06/11 09:35

题意:给出一个字符串,求其 本质不同的 回文子串的个数。


如果有小伙伴WA了无数次,请尝试模拟一下aabaa这个串,答案应该是5。(本菜鸡就WA了一晚上)


题解:回文子串可以考虑先来个O(n)的马拉车预处理,这样每个回文子串长度必然是计数,那么我们可以统计本质不同的(正中间的字符+右半边串)回文子串个数。然后可以考虑用后缀自动机统计答案。这道题的关键的关键在于去重的处理。去重要求去掉:h[i]范围内已经被统计过的串。那么可以用一个变量维护 目前已经被统计过的长度。要注意到h数组和马拉车的lc数组是没什么关系的。


Code:

#include<bits/stdc++.h>using namespace std;#define rank rkconst int MAX = 2e5+10000;char ch[MAX];int cntA[MAX],cntB[MAX],A[MAX],B[MAX],tsa[MAX],rank[MAX],SA[MAX],lc[MAX],h[MAX];int n,t;int Cas =1; void init(){    memset(ch,0,sizeof ch);    ch[0]='z'+1;}void input(){    scanf("%s",ch+1);    n =  strlen(ch+1);    ch[n*2+1]='#';    for (int i=n;i>=1;i--){        ch[i*2] = ch[i];        ch[i*2-1] ='#';    }    n = n*2+1;    ch[n+1]='\0';}void get_SA(){    for (int i=0;i<=10000;i++) cntA[i]=0;    for (int i=1;i<=n;i++) cntA[ch[i]]++;    for (int i=1;i<=10000;i++) cntA[i]+=cntA[i-1];    for (int i=n;i>=1;i--) SA[cntA[ch[i]]--] =i;    rank[SA[1]]=1;    for (int i=2;i<=n;i++){        rank[SA[i]]=rank[SA[i-1]];        if (ch[SA[i]]!=ch[SA[i-1]]) rank[SA[i]]++;    }    for (int step = 1;rank[SA[n]]<n;step<<=1){        for (int i=0;i<=n;i++)cntA[i]=cntB[i]=0;        for (int i=1;i<=n;i++){            cntA[A[i]=rank[i]]++;            cntB[B[i]=(i+step<=n)?rank[i+step]:0]++;        }        for (int i=1;i<=n;i++) cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1];        for (int i=n;i>=1;i--) tsa[cntB[B[i]]--] =i;        for (int i=n;i>=1;i--) SA[cntA[A[tsa[i]]]--] = tsa[i];        rank[SA[1]]=1;        for (int i=2;i<=n;i++){            rank[SA[i]]=rank[SA[i-1]];            if (A[SA[i]]!=A[SA[i-1]]||B[SA[i]]!=B[SA[i-1]]) rank[SA[i]]++;        }    }}void get_Height(){    for (int i=1,j=0;i<=n;i++){        if (j) j--;        while (ch[i+j]==ch[SA[rank[i]-1]+j])j++;        h[rank[i]]=j;    }}void Manacher(){    lc[1]=1;    int k=1;    for (int i=2;i<=n;i++){//        printf("%d %d\n",i,k);        int p = k+lc[k]-1;        if (i<=p){            lc[i]=min(lc[2*k-i],p-i+1);        }else{            lc[i]=1;        }        while (ch[i+lc[i]]==ch[i-lc[i]])lc[i]++;        if (i+lc[i]>k+lc[k])k=i;    }}void print(){    printf("%s\n",ch+1);    for (int i=1;i<=n;i++){        printf("%s %d\n",ch+SA[i],lc[SA[i]]);    }}void solve(){    get_SA();    get_Height();    Manacher();    print();    long long res =0;//    cout<<"1: "<<res<<endl;int cnt=0;    for (int i=2;i<=n;i++){    cnt = min(cnt,h[i]);        res+=max(0,lc[SA[i]]-min(h[i],cnt));  //      cout<<i<<" "<<res<<endl;        if (lc[SA[i]]>cnt){        cnt = lc[SA[i]];        }    }//    cout<<res/2<<endl;    printf("Case #%d: %I64d\n",Cas++,res/2);}int main(){    scanf("%d",&t);    while (t--){        init();        input();        solve();    }    return 0;}


阅读全文
0 0
原创粉丝点击