HDU - 3948 后缀数组+Manacher

 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3948

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

思路:主要参考该篇解题报告

先按照manacher的构造方法改造一遍串,然后跑一遍manacher。求出以i为中心的最长回文串长度p[i]。

然后跑一遍后缀数组,若已经求得后缀sa[i-1]对答案的贡献,然后现在计算后缀sa[i],本来是要加上以sa[i]为中心的回文串的个数p[sa[i]]。

我们可以维护一个tmp,也就是上图中蓝色的框。tmp表示以字符sa[i-1]为中心已经被统计过的回文串的个数。到了当前的sa[i],tmp=min(tmp,h[i]);
每次如果p[x]<=tmp,就continue;否则,ans+=(p[x]-tmp)/2;(/2是因为有#)

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>  
#include<string.h>  
#include<cstring>
#include<algorithm>  
#include<queue>  
#include<math.h>  
#include<time.h>
#include<vector>
#include<iostream>
#include<map>
using namespace std;
typedef long long int LL;
const int MAXN = 100000*3  + 10;
int wa[MAXN],wb[MAXN],wv[MAXN],Ws[MAXN];
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){ //??????sa????????(len+1)???????
     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];
       for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
       x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     }
     return;
}
int Rank[MAXN],height[MAXN]; //height[0]:sa[1]?sa[0]?lcp
void calheight(int *r,int *sa,int n){ //??????sa???????(len)
     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++);
     return;
}
int RMQ[MAXN],mm[MAXN],best[20][MAXN];
void initRMQ(int n){
     int i,j,a,b;
     for(mm[0]=-1,i=1;i<=n;i++)
     mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
     for(i=1;i<=n;i++) best[0][i]=i;
     for(i=1;i<=mm[n];i++)
     for(j=1;j<=n+1-(1<<i);j++){
       a=best[i-1][j];
       b=best[i-1][j+(1<<(i-1))];
       if(RMQ[a]<RMQ[b]) best[i][j]=a;
       else best[i][j]=b;
     }
     return;
}
int askRMQ(int a,int b){
    int t;
    t=mm[b-a+1];b-=(1<<t)-1;
    a=best[t][a];b=best[t][b];
    return RMQ[a]<RMQ[b]?a:b;
}
int lcp(int a,int b){
    int t;
    a=Rank[a];b=Rank[b];
    if(a>b) {t=a;a=b;b=t;}
    return(height[askRMQ(a+1,b)]);
}
char str[MAXN],dstr[MAXN];
int lenstr,lendstr,p[MAXN],r[MAXN],sa[MAXN];
void init(char *s){
    dstr[0]='$'; dstr[1]='#';
    for(int i=0;i<lenstr;i++){
        dstr[i*2+2]=str[i]; dstr[i*2+3]='#';
    }
    lendstr=lenstr*2+2; dstr[lendstr]='*';
}
void manacher(){
    memset(p,0,sizeof(p)); int id=0,mx=0;
    for(int i=1;i<lendstr;i++){
        if(mx>i){ p[i]=min(p[2*id-i],mx-i); }
        else{ p[i]=1; }
        while(dstr[i-p[i]]==dstr[i+p[i]]){ p[i]++; }
        if(p[i]+i>mx){  mx=p[i]+i; id=i; }
    }
}
void solve(){
    int ans=0,tmp=0;
    for(int i=1;i<=lendstr;i++){
        tmp=min(tmp,height[i]);
        if(p[sa[i]]<=tmp){
            continue;    
        }
        ans+=(p[sa[i]]-tmp)/2;
        tmp=p[sa[i]];
    }
    printf("%d\n",ans);
}
int main(){
//#ifdef kirito
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//#endif
//    int start = clock();
    int t,Case=1;
    scanf("%d",&t);
    while (t--){
        scanf("%s",str); lenstr=strlen(str); init(str); manacher();
        for(int i=0;i<=lendstr;i++){
            if(i==lendstr){r[i]=0; continue;}
            r[i]=(int)dstr[i];
        }
        da(r, sa, lendstr+1,256);
        calheight(r, sa, lendstr);
//        printf("len=%d\n",lendstr);
        printf("Case #%d: ",Case++); solve();
    }
//#ifdef LOCAL_TIME
//    cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
    return 0;
}

 

posted @ 2016-10-12 11:39  キリト  阅读(276)  评论(0编辑  收藏  举报