当前位置: 代码迷 >> 综合 >> 【UVA 12338 Anti-Rhyme Pairs】 后缀数组+ST表
  详细解决方案

【UVA 12338 Anti-Rhyme Pairs】 后缀数组+ST表

热度:84   发布时间:2023-12-29 02:49:48.0

UVA12338
本题题意是给你n个字符串,m次查询,查询两个字符串的最长公共前缀
我们只需要把n个字符串记录下标之后进行拼接,放进后缀数组之后,然后利用st表预处理求任意两个后缀的lcp就可以了,任意两个后缀的最长公共前缀,就是求sa中两个后缀之间的height最小值。
UVA 12338代码

#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;
const int maxn = 2e6+2;//开总串长度
int wa[maxn],wb[maxn],wsf[maxn],wv[maxn],sa[maxn];
int rank_[maxn],height[maxn],s[maxn];
char str[maxn];
int cmp(int *r,int a,int b,int k)
{return r[a]==r[b]&&r[a+k]==r[b+k];
}void getsa(int *r,int *sa,int n,int m)//n为添加0后的总长
{int i,j,p,*x=wa,*y=wb,*t;for(i=0; i<m; i++)  wsf[i]=0;for(i=0; i<=n; i++)  wsf[x[i]=r[i]]++;for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];for(i=n; i>=0; i--)  sa[--wsf[x[i]]]=i;p=1;j=1;for(; p<=n; j*=2,m=p){for(p=0,i=n+1-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++)  wsf[i]=0;for(i=0; i<=n; i++)  wsf[wv[i]]++;for(i=1; i<m; i++)  wsf[i]+=wsf[i-1];for(i=n; i>=0; i--)  sa[--wsf[wv[i]]]=y[i];t=x;x=y;y=t;x[sa[0]]=0;for(p=1,i=1; i<=n; i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)? p-1:p++;}
}void getheight(int *r,int n)//n为添加0后的总长
{int i,j,k=0;for(i=1; i<=n; i++)  rank_[sa[i]]=i;for(i=0; i<n; i++){if(k)k--;elsek=0;j=sa[rank_[i]-1];while(r[i+k]==r[j+k])k++;height[rank_[i]]=k;}
}
int posx[maxn];
inline int min_(int x,int y){
   return x<y?x:y;}
int p,l,r;
int f[2*maxn][50];
int strle[maxn];
int main()
{int t;int n,m;int casee=1;scanf("%d",&t);while(t--){p=0;int cnt=0;int pos=30;scanf("%d",&n);for(int i=0;i<n;i++){scanf("%s",str);int len=strlen(str);posx[i+1]=cnt;strle[i+1]=len;for(int j=0;j<len;j++)s[cnt++]=str[j]-'a'+1;s[cnt++]=pos++;}s[cnt]=0;getsa(s,sa,cnt,pos);getheight(s,cnt);for(int i=1;i<=cnt;i<<=1) p++;for(int i=1;i<=cnt;i++) f[i][0]=height[i];for(int j=1;j<p;j++)for(int i=1;i<=cnt;i++)if(i+(1<<j-1)>cnt) f[i][j]=f[i][j-1];else f[i][j]=min_(f[i][j-1],f[i+(1<<j-1)][j-1]);scanf("%d",&m);printf("Case %d:\n",casee++);while(m--){int x,y;scanf("%d%d",&x,&y);if(x==y){printf("%d\n",strle[x]);continue;}int rk1=rank_[posx[x]];//获取在sa中的排名int rk2=rank_[posx[y]];if(rk1<rk2){l=rk1+1;r=rk2;p=log2(r-l+1);printf("%d\n",min_(f[l][p],f[r-(1<<p)+1][p]));}else{l=rk2+1;r=rk1;p=log2(r-l+1);printf("%d\n",min_(f[l][p],f[r-(1<<p)+1][p]));}}}return 0;
}
  相关解决方案