# ACM常用模板——数据结构——后缀数组

348人阅读 评论(0)

#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<algorithm>#include<set>#include<map>#include<queue>#include<vector>#define maxn 1000005#define pb push_back#define LL longlong#define MS(a,b) memset(a,b,sizeof(a))#define FI(a,b) fill(a,a+maxn,b)#define sf(n) scanf("%d",&n)#define sf2(a,b) scanf("%d%d",&a,&b)#define pf(n) printf("%d\n",n)#define ffr(i,n)for(i=0;i<n;i++)usingnamespace std;intRank[maxn],tmp[maxn],sa[maxn],height[maxn];int n,k;bool compare_sa(int i,int j){if(Rank[i]!=Rank[j])returnRank[i]<Rank[j];else{int ri=i+k<=n?Rank[i+k]:-1;int rj=j+k<=n?Rank[j+k]:-1;return ri<rj;}}//计算字符串后缀数组savoid constru_sa(string S){int i;    n=S.length();for(i=0;i<=n;i++){        sa[i]=i;Rank[i]=i<n?S[i]:-1;}for(k=1;k<=n;k*=2){        sort(sa,sa+n+1,compare_sa);        tmp[sa[0]]=0;for(i=1;i<=n;i++){            tmp[sa[i]]=tmp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0);}for(i=0;i<=n;i++){Rank[i]=tmp[i];}}}//高度数组height[i]:代表第i和i+1个后缀的最长公共前缀void construct_lcp(string S){int n=S.length(),i;for(i=0;i<=n;i++)Rank[sa[i]]=i;int h=0;    height[0]=0;for(i=0;i<n;i++){int j=sa[Rank[i]-1];if(h>0)h--;for(;j+h<n&&i+h<n;h++){if(S[j+h]!=S[i+h])break;}        height[Rank[i]]=h;}}//字符串匹配int contain(string S,string T){int a=0,b=S.length();while(b-a>1){int c=(a+b)/2;if(S.compare(sa[c],T.length(),T)<0)a=c;else b=c;}if(S.compare(sa[b],T.length(),T)==0)return sa[b];elsereturn-1;}int main(){    string s,t;int i;while(cin>>s>>t){//s是原串，t是匹配串        constru_sa(s);        construct_lcp(s);int len=s.size();        printf("sa: \n");for(i=0;i<=len;i++){printf("%d ",sa[i]);}printf("\n");        printf("rank: \n");for(i=0;i<=len;i++){printf("%d ",Rank[i]);}printf("\n");        printf("height: \n");for(i=0;i<=len;i++){printf("%d ",height[i]);}printf("\n");        cout<<contain(s,t)<<endl;}return0;}

(一)最长公共前缀

height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公

rank[j]<rank[k],则有以下性质：

suffix(j) 和 suffix(k) 的 最 长 公 共 前 缀 为 height[rank[j]+1],

height[rank[j]+2], height[rank[j]+3], … ,height[rank[k]]中的最小值。

hdu4691

#include<cstdio>#include<cstring>#include<algorithm>usingnamespace std;#define LL longlong#define N 100010char s[N];int m,n,len;int t[N],t2[N],c[N],height[N],sa[N],rank[N],dp[N][20],cnt[N];//sa   代表等级为i的下标//rank  代表下标为i的等级//height  代表字符串由最低位排序到最高位相邻两个字符串的前缀相同个数 void build_sa(){    m=27;int*x=t,*y=t2;for(int i=0; i<m;++i) c[i]=0;for(int i=0; i<n;++i)++c[x[i]=cnt[i]];for(int i=1; i<m;++i) c[i]+=c[i-1];for(int i=n-1; i>=0;--i) sa[--c[x[i]]]=i;for(int k=1; k<=n; k<<=1){int p=0;for(int i=n-k; i<n;++i) y[p++]=i;for(int i=0; i<n;++i)if(k<=sa[i]) y[p++]=sa[i]-k; for(int i=0; i<m;++i) c[i]=0;for(int i=0; i<n;++i)++c[x[y[i]]];for(int i=1; i<m;++i) c[i]+=c[i-1];for(int i=n-1; i>=0;--i) sa[--c[x[y[i]]]]=y[i];         swap(x,y);        p=1,x[sa[0]]=0;for(int i=1; i<n;++i)            x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++;if(p>=n)break;        m=p;}} void get_height(){for(int i=0; i<=len;++i) rank[sa[i]]=i;for(int i=0,k=0; i<len;++i){if(k)--k;if(rank[i]-1<0)continue;int j=sa[rank[i]-1];while(cnt[i+k]==cnt[j+k])++k;        height[rank[i]]=k;}}
int RMQ(int L,int R){int k=0;while((1<<(k+1))<=R-L+1)++k;return  min(dp[L][k],dp[R-(1<<k)+1][k]);} void RMQ_init(){for(int i=0; i<=len;++i)  dp[i][0]=height[i];for(int j=1;(1<<j)<=len;++j)for(int i=1; i+(1<<j)-1<=len;++i)            dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);} int lcp(int a,int l){if(a==l)return len-a;int u=rank[a],v=rank[l];if(u>v)return RMQ(v+1,u);elsereturn RMQ(u+1,v);} int cal(int p){int v=p;for(int i=1;;++i)if(v/10==0)return i;else v/=10;}int main(){// freopen("in.txt","r",stdin);while(scanf("%s",s)!=EOF){        len=strlen(s);for(int i=0; i<len;++i) cnt[i]=s[i]-'a'+1;        cnt[len]=0;        n=len+1;        build_sa();        get_height();        RMQ_init();int t,a,b,l,r;        LL ans1,ans2;        scanf("%d",&t);        scanf("%d %d",&a,&b);        ans1=b-a+1;        ans2=b-a+3;--t;while(t--){            scanf("%d %d",&l,&r);            ans1=ans1+r-l+1;int p=min(lcp(a,l),min(b-a,r-l));            ans2=ans2+(r-l)-p+2+cal(p);            a=l,b=r;}        printf("%I64d %I64d\n",ans1,ans2);}return0;}

（二）重复子串：

（三）不可重叠最长重复子串（pku1743）

#define maxn 20010int wa[maxn],wb[maxn],wv[maxn],wss[maxn];int r[maxn],sa[maxn];int cmp(int*r,int a,int b,int l){return r[a]==r[b]&& r[a+l]==r[b+l];}/*【倍增算法O(nlgn)】待排序的字符串放在r 数组中，从r[0]到r[n-1]，长度为n，且最大值小于m  使用倍增算法前，需要保证r数组的值均大于0。然后要在原字符串后添加一个0号字符  所以，若原串的长度为n，则实际要进行后缀数组构建的r数组的长度应该为n+1.所以调用da函数时，对应的n应为n+1.*/void da(int*r,int*sa,int n,int m){//n要加1int i,j,p,*x=wa,*y=wb,*t;for(i=0;i<m;i++) wss[i]=0;for(i=0;i<n;i++) wss[x[i]=r[i]]++;for(i=1;i<m;i++) wss[i]+=wss[i-1];for(i=n-1;i>=0;i--) sa[--wss[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++) wss[i]=0;for(i=0;i<n;i++) wss[wv[i]]++;for(i=1;i<m;i++) wss[i]+=wss[i-1];for(i=n-1;i>=0;i--) sa[--wss[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];//rank[i]：i排第几；sa[i]：排第i的后缀串在哪里，互为逆运算 void calheight(int*r,int*sa,int n){//n不用加1int 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 main(){int n;while(scanf("%d",&n)&& n){int i;int x,y;        scanf("%d",&x);for(i=0;i<n-1;i++){            scanf("%d",&y);            r[i]= y - x +100;//不能出现负数            x = y;}cout<<endl;        r[n-1]=0;//总共有n-1个值        da(r,sa,n,190);        calheight(r,sa,n-1);for(i=1;i<=n-1;i++)        cout<<height[i]<<endl;int l =0,r = n-1;int mid;int ans=0;while(l<=r){            mid =(l+r)>>1;int minm = sa[1];int maxm = sa[1];bool ok =0;for(i=2;i<=n;i++){//不写i<=n-1的原因系这样可以处理完最后一组if(height[i]>=mid && i!=n){if(sa[i]>maxm)maxm = sa[i];if(sa[i]<minm)minm = sa[i];}else{if(maxm - minm>=mid){                        ok =1;break;}else minm = maxm = sa[i];}}if(ok){                ans = mid;                l = mid+1;}else r = mid-1;}//ans+1的原因是前面的处理是把后一个减去前一个的值，所以最后要+1个if(ans+1<=4)printf("%d\n",0);else printf("%d\n",ans+1);}return0;}
（四）可重叠的k次最长重复子串（pku3261）

/*PKU3261 Milk Patterns*/#include<stdio.h>#include<memory.h>#include<stdlib.h>#define MAX(a,b)((a)>(b)?(a):(b))#define MIN(a,b)((a)>(b)?(b):(a))#define N 20005#define K 35int nday;/***************************************/int power;int lstrank[N];int cmpstr[N];int cmpChar(constvoid*a,constvoid*b){return cmpstr[*(int*)a]- cmpstr[*(int*)b];}int cmpLst(constvoid*A,constvoid*B){int a =*(int*)A;int b =*(int*)B;if(lstrank[a]==lstrank[b])return lstrank[a+power]-lstrank[b+power];return lstrank[a]-lstrank[b];}/*后缀数组参数：    输入字符串str[];    返回后缀数组sa[];返回名次数组rank[]说明：    复杂度O(nlogn)    需要stdlib.h辅助全局变量power, lstrank[],cmpstr[]*/void suffixArray(int str[],int sa[],int rank[]){int i,j,n=nday;for(i=0;i<n;i++) sa[i]=i;    memcpy(cmpstr,str,sizeof(cmpstr));    qsort(sa,n,sizeof(int),cmpChar);for(i=j=0;i<n;i++){if(i>0&& str[sa[i]]!=str[sa[i-1]]) j++;        rank[sa[i]]=j;}for(power=1;rank[sa[n-1]]<n-1; power*=2){        memcpy(lstrank,rank,sizeof(int)*n);        qsort(sa,n,sizeof(int), cmpLst);for(i=j=0;i<n;i++){if(i>0&&cmpLst(&sa[i-1],&sa[i])) j++;            rank[sa[i]]=j;}}}/*区间最大值询问    preRMQ()用O(nlogn)时间预处理    RMQ()用O(1)的时间询问i~j之间的最大值*/int dr[N][K]={0};void preRMQ(int a[],int n){int i,j,k,f,s;for(i=0;i<n;i++) dr[i][0]=a[i];for(s=f=1;s<n;f++){for(i=0;;i++){if(i+s>=n)break;            dr[i][f]= MIN(dr[i][f-1],dr[i+s][f-1]);}        s=1<<f;}}int RMQ(int p,int q){int d,f;    d=q-p+1;for(f=0;(1<<f)<=d;f++); f--;return MIN(dr[p][f],dr[q-(1<<f)+1][f]);}/*预处理LCP求h[],height[]参数：    输入原字符串str[]    输入后缀数组sa[]    输入名次数组rank[]    返回height[]说明：    复杂度O(n)    需要事先用suffixArray计算sa[]和rank[]    height[i]=LCP(i-1,i)    h[i]=height[rank[i]]    height[i]=h[sa[i]]*/void preLCP(int str[],int sa[],int rank[],int height[]){int i,j,k,s,n=nday;int h[N]; for(i=0;i<n;i++){if(rank[i]==0){            h[i]=0;continue;}        j=rank[i]-1;        k=rank[i];if(i==0||h[i-1]<=1) s=0;else s=h[i-1]-1;for(;sa[k]+s<n && sa[j]+s<n;s++)if(str[sa[k]+s]!= str[sa[j]+s])break;        h[i]=s;}for(i=0;i<n;i++) height[rank[i]]= h[i];    preRMQ(height,n);}/*LCP询问后缀数组sa[]中x和y的最长公共前缀，复杂度O(logn)*/int LCP(int x,int y){if(x<y)return RMQ(x+1,y);elsereturn RMQ(y+1,x);}/**************************************/int n,m;int str[N];int sa[N];int rank[N];int height[N];void printa(int a[]){int i;for(i=0;a[i];i++) printf("%d",a[i]-1);    puts("");}int main(){int i,j,k;int ans; while(scanf("%d%d",&n,&m)!=EOF){        nday=n+1;for(i=0;i<n;i++){            scanf("%d",&str[i]); str[i]++;}        str[n]=0;        suffixArray(str,sa,rank);        preLCP(str,sa,rank,height);/*        for(i=0;i<n;i++){            printf("%d - %d: ",i,sa[i]);            printa(str+sa[i]);        }*/        ans=0;for(i=0,j=m-1;j<=n;i++,j++){            k=LCP(i,j);            ans=MAX(ans,k);}        printf("%d/n",ans);}return0;}
（五）

/* *Author:       Zhaofa Fang *Created time: 2013-04-21-21.19 *Language:     C++ */#include<cstdio>#include<cstdlib>#include<sstream>#include<iostream>#include<cmath>#include<cstring>#include<algorithm>#include<string>#include<utility>#include<vector>#include<queue>#include<map>#include<set>usingnamespace std; typedeflonglong ll;#define DEBUG(x) cout<<#x << ':' << x << endl#define FOR(i,s,t)for(int i =(s);i <=(t);i++)#define FORD(i,s,t)for(int i =(s);i >=(t);i--)#define REP(i,n) FOR(i,0,n-1)#define REPD(i,n) FORD(i,n-1,0)#define PII pair<int,int>#define PB push_back#define MP make_pair#define ft first#define sd second#define lowbit(x)(x&(-x))#define INF (1<<30) constint maxn =1111;char s[maxn];int sa[maxn],t1[maxn],t2[maxn],c[maxn];int rank[maxn],height[maxn]; void getHeight(int n){int k =0;for(int i=1;i<=n;i++)rank[sa[i]]= i;for(int i=0;i<n;i++){if(k)k--;int j = sa[rank[i]-1];while(s[i+k]==s[j+k])k++;        height[rank[i]]= k;}}bool cmp(int*r,int a,int b,int l){return(r[a]==r[b]&& r[a+l]==r[b+l]);}void build_sa(int m,int n){int i,*x=t1,*y=t2,k,p;for( i=0;i<m;i++)c[i]=0;for( i=0;i<n;i++)c[x[i]= s[i]]++;for( i=1;i<m;i++)c[i]+= c[i-1];for( i=n-1;i>=0;i--)sa[-- c[x[i]]]= i;for(k=1,p=0;p<n;m=p,k<<=1){        p =0;for(i=n-k;i<n;i++)y[p++]= i;for(i=0;i<n;i++)if(sa[i]>=k)y[p++]= sa[i]-k;for(i=0;i<m;i++)c[i]=0;for(i=0;i<n;i++)c[x[y[i]]]++;for(i=1;i<m;i++)c[i]+= c[i-1];for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]= y[i];        swap(x,y);        p =1; x[sa[0]]=0;for(i=1;i<n;i++)            x[sa[i]]= cmp(y,sa[i-1],sa[i],k)?p-1:p++;}    getHeight(n-1);}int solve(int n){int ans = n - sa[1];for(int i=2;i<=n;i++){        ans += n-sa[i]-height[i];}return ans;}int main(){//freopen("in","r",stdin);//freopen("out","w",stdout);int T;    cin>>T;while(T--){        scanf("%s",s);int n = strlen(s);        build_sa(255,n+1);        printf("%d\n",solve(n));}return0;}
（六）

#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#define MS(a,b) memset(a,b,sizeof(a))usingnamespace std;constint maxn=200010;char s[maxn];int w[maxn],wa[maxn],wb[maxn],wv[maxn],x[maxn],sa[maxn],Rank[maxn],height[maxn],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 n,int m)//n:L,m:kind{int i,j,p,*x=wa,*y=wb,*t;for(i=0; i<m; i++) w[i]=0;for(i=0; i<n; i++) w[x[i]=s[i]]++;for(i=1; i<m; i++) w[i]+=w[i-1];for(i=n-1; i>=0; i--) sa[--w[x[i]]]=i;for(p=1,j=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<m; i++) w[i]=0;for(i=0; i<n; i++) w[wv[i]=x[y[i]]]++;for(i=1; i<m; i++) w[i]+=w[i-1];for(i=n-1; i>=0; i--) sa[--w[wv[i]]]=y[i];for(t=x,x=y,y=t,p=1,i=1,x[sa[0]]=0; i<n; i++)            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;}return;}void cal(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]; s[i+k]==s[j+k]; k++);return;}int main(){//freopen("F:\\in.txt","r",stdin);int len,l,ans;while(~scanf("%s",s)){        l=strlen(s);char s1[maxn];        MS(s1,0);        strcpy(s1,s);        reverse(s1,s1+strlen(s1));        s[l]='#';        strncat(s,s1,l);        len=strlen(s);        da(len+1,'z'+1);//sa start 0        cal(len);        ans=0;//cout<<s<<endl;for(int i=1;i<=len;i++){//cout<<sa[i]<<' '<<sa[i-1]<<' '<<ans<<endl;if(sa[i]<l&&sa[i-1]>l||sa[i]>l&&sa[i-1]<l)                ans=max(ans,height[i]);}        printf("%d\n",ans);        MS(s,0);}return0;}
(七)连续重复串：如果一个字符串L是由某个字符串S重复R次而得到的，则称

L是一个连续重复串。R是这个字符串的重复次数。

（八）重复次数最多的连续重复子串(spoj687,pku3693)

// File Name: 3693.cpp// Author: Zlbing// Created Time: 2013年09月06日 星期五 21时05分32秒 #include<iostream>#include<string>#include<algorithm>#include<cstdlib>#include<cstdio>#include<set>#include<map>#include<vector>#include<cstring>#include<stack>#include<cmath>#include<queue>usingnamespace std;#define CL(x,v); memset(x,v,sizeof(x));#define INF 0x3f3f3f3f#define LL longlong#define REP(i,r,n)for(int i=r;i<=n;i++)#define RREP(i,n,r)for(int i=n;i>=r;i--)//rank从0开始//sa从1开始,因为最后一个字符(最小的)排在第0位//height从2开始,因为表示的是sa[i-1]和sa[i]constint MAXN=220000;int rank[MAXN],sa[MAXN],X[MAXN],Y[MAXN],height[MAXN];char s[MAXN];int buc[MAXN];void calheight(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]; s[i+k]== s[j+k]; k++);}bool cmp(int*r,int a,int b,int l){return(r[a]== r[b]&& r[a+l]== r[b+l]);}void suffix(int n,int m =128){int i , l , p ,*x = X ,*y = Y;for(i =0; i < m ; i ++) buc[i]=0;for(i =0; i < n ; i ++) buc[ x[i]= s[i]]++;for(i =1; i < m ; i ++) buc[i]+= buc[i-1];for(i = n -1; i >=0; i --) sa[--buc[ x[i]]]= i;for(l =1,p =1; p < n ; m = p , l *=2){        p =0;for(i = n-l ; i < n ; i ++) y[p++]= i;for(i =0; i < n ; i ++)if(sa[i]>= l) y[p++]= sa[i]- l;for(i =0; i < m ; i ++) buc[i]=0;for(i =0; i < n ; i ++) buc[ x[y[i]]]++;for(i =1; i < m ; i ++) buc[i]+= buc[i-1];for(i = n -1; i >=0; i --) sa[--buc[ x[y[i]]]]= y[i];for(swap(x,y), x[sa[0]]=0, i =1, p =1; i < n ; i ++)            x[ sa[i]]= cmp(y,sa[i-1],sa[i],l)? p-1: p++;}    calheight(n-1);//后缀数组关键是求出height,所以求sa的时候顺便把rank和height求出来}//当需要反复询问两个后缀的最长公共前缀时用到RMQintLog[MAXN];int best[20][MAXN];void initRMQ(int n){//初始化RMQfor(int i =1; i <= n ; i ++) best[0][i]= height[i];for(int i =1; i <=Log[n]; i ++){int limit = n -(1<<i)+1;for(int j =1; j <= limit ; j ++){            best[i][j]= min(best[i-1][j], best[i-1][j+(1<<i>>1)]);}}}int lcp(int a,int b){//询问a,b后缀的最长公共前缀    a = rank[a];    b = rank[b];if(a > b) swap(a,b);    a ++;int t =Log[b - a +1];return min(best[t][a], best[t][b -(1<<t)+1]);}int main(){//预处理每个数字的Log值,常数优化,用于RMQLog[0]=-1;for(int i =1; i < MAXN ; i ++){Log[i]=(i&(i-1))?Log[i-1]:Log[i-1]+1;}int cas=0;//*******************************************//    n为数组长度,下标0开始//    将初始数据,保存在s里,并且保证每个数字都比0大//    m = max{ s[i] } + 1//    一般情况下大多是字符操作,所以128足够了//*******************************************while(~scanf("%s",s)){if(s[0]=='#')break;int n=strlen(s);        s[n]=0;        suffix(n+1);        initRMQ(n);int maxx=0;int len=0;int pos=0;for(int i=1;i<=n/2;i++){for(int j=0;j+i<n;j+=i){if(s[j]!=s[j+i])continue;int k=lcp(j,j+i);int tot=k/i+1;int t=i-(k%i);int p=j;int cnt=0;if(t&&t<i){for(int m=j-1;m>j-i&&s[m]==s[m+i]&&m>=0;m--){                       cnt++;if(cnt==t){                           tot++;                           p=m;}elseif(rank[p]>rank[m]){                           p=m;}}}if(tot>maxx){                   maxx=tot;                   pos=p;                   len=maxx*i;}elseif(tot==maxx){if(rank[p]<rank[pos]){                       pos=p;                       len=maxx*i;}}}}        printf("Case %d: ",++cas);if(maxx<2){char ch='z';for(int i=0;i<n;i++)if(s[i]<ch)                    ch=s[i];            printf("%c\n",ch);continue;}for(int i=pos;i<pos+len;i++)            printf("%c",s[i]);        printf("\n");} return0;}

（九）公共子串:如果字符串L同时出现在字符串A和字符串B中，则称字符串L 是字符串A和字符串B的公共子串。

### 子串的个数

A=“xx”，B=“xx”，k=1，长度不小于k的公共子串的个数是5。

A=“aababaa”，B=“abaabaa”，k=2，长度不小于k的公共子串的个数是22。

#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#define MS(a,b) memset(a,b,sizeof(a))usingnamespace std;constint maxn=200010;char s[maxn];int w[maxn],wa[maxn],wb[maxn],wv[maxn],x[maxn],sa[maxn],Rank[maxn],height[maxn],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 n,int m)//n:L,m:kind{int i,j,p,*x=wa,*y=wb,*t;for(i=0; i<m; i++) w[i]=0;for(i=0; i<n; i++) w[x[i]=s[i]]++;for(i=1; i<m; i++) w[i]+=w[i-1];for(i=n-1; i>=0; i--) sa[--w[x[i]]]=i;for(p=1,j=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<m; i++) w[i]=0;for(i=0; i<n; i++) w[wv[i]=x[y[i]]]++;for(i=1; i<m; i++) w[i]+=w[i-1];for(i=n-1; i>=0; i--) sa[--w[wv[i]]]=y[i];for(t=x,x=y,y=t,p=1,i=1,x[sa[0]]=0; i<n; i++)            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;}return;}void cal(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]; s[i+k]==s[j+k]; k++);return;}int main(){//freopen("F:\\in.txt","r",stdin);int len,l,ans,t,m,r,i,ll,rr;    scanf("%d",&t);while(t--){        scanf("%s%d",s,&m);        len=strlen(s);        da(len+1,'z'+1);//sa start 0        cal(len);while(m--){            scanf("%d%d",&l,&r);int d=r-l+1;            ans=0;            ll=Rank[l-1];            rr=Rank[r-1];if(ll>rr)swap(rr,ll);int flag=0;for(i=0;i<=len;i++){                ans+=d-sa[i]-height[i];//cout<<i<<' '<<sa[i]<<' '<<l<<' '<<r<<' '<<height[i]<<endl;}            printf("%d\n",ans);}}return0;} 

### 2.4多个字符串的相关问题

（判断能否做到不重叠，如果题目中没有不重叠的要求，那么不用做此判断）。

#include<stdio.h>#include<iostream>#include<cstring>#include<map>#define MS(a,b) memset(a,b,sizeof(a))#define INF 1<<29usingnamespace std;constint maxn=200010;string s;int w[maxn],wa[maxn],wb[maxn],wv[maxn],x[maxn],sa[maxn],Rank[maxn],height[maxn],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 n,int m)//n:L,m:kind{int i,j,p,*x=wa,*y=wb,*t;for(i=0; i<m; i++) w[i]=0;for(i=0; i<n; i++) w[x[i]=s[i]]++;for(i=1; i<m; i++) w[i]+=w[i-1];for(i=n-1; i>=0; i--) sa[--w[x[i]]]=i;for(p=1,j=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<m; i++) w[i]=0;for(i=0; i<n; i++) w[wv[i]=x[y[i]]]++;for(i=1; i<m; i++) w[i]+=w[i-1];for(i=n-1; i>=0; i--) sa[--w[wv[i]]]=y[i];for(t=x,x=y,y=t,p=1,i=1,x[sa[0]]=0; i<n; i++)            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;}return;}void cal(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]; s[i+k]==s[j+k]; k++);return;}int solve(int i,int n){int ans=0,max1=-1,min1=INF,j;for(j=2;j<=n;j++){if(height[j]>=i)//由于height[i]是rank[i]和rank[i]-1的最长公共前缀，rank是排序了，所以{//如果连续if而没有else，重复子串也不会变            max1=max(sa[j-1],max(max1,sa[j]));            min1=min(sa[j-1],min(min1,sa[j]));}else{if(min1!=INF&&max1!=-1&&max1-min1>=i)//判断长度为i的重复子串是否重叠            ans++;            max1=-1;            min1=INF;}}if(min1!=INF&&max1!=-1&&max1-min1>=i)    ans++;return ans;}int main(){//freopen("F:\\in.txt","r",stdin);int l,j,k;while(cin>>s){if(s=="#")break;        l=s.size();        s[l]='#';        da(l+1,'z'+1);//sa start 0        cal(l);        __int64 ans=0;for(int i=1;i<=l/2;i++){            ans+=solve(i,l);}        printf("%I64d\n",ans);}return0;}

0
0

* 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场
个人资料
• 访问：10434次
• 积分：305
• 等级：
• 排名：千里之外
• 原创：21篇
• 转载：2篇
• 译文：0篇
• 评论：3条
文章分类
阅读排行
评论排行
最新评论