后缀数组模板
来源:互联网 发布:jenkins部署php 编辑:程序博客网 时间:2024/04/28 02:42
转自 学长
template <typename T, int LEN>struct suffixarray{ int str[LEN*3],sa[LEN*3]; int rank[LEN],height[LEN]; int id[LEN]; int best[LEN][20]; int len; bool equal(int *str, int a, int b) { return str[a]==str[b]&&str[a+1]==str[b+1]&&str[a+2]==str[b+2]; } bool cmp3(int *str, int *nstr, int a, int b) { if(str[a]!=str[b]) return str[a]<str[b]; if(str[a+1]!=str[b+1]) return str[a+1]<str[b+1]; return nstr[a+b%3]<nstr[b+b%3]; } void radixsort(int *str, int *sa, int *res, int n, int m) { int i; for(i=0;i<m;++i) id[i]=0; for(i=0;i<n;++i) ++id[str[sa[i]]]; for(i=0;i<m;++i) id[i+1]+=id[i]; for(i=n-1;i>=0;--i) res[--id[str[sa[i]]]]=sa[i]; } void dc3(int *str, int *sa, int n, int m) { #define F(x) ((x)/3+((x)%3==1?0:one)) #define G(x) ((x)<one?(x)*3+1:((x)-one)*3+2) int *nstr=str+n, *nsa=sa+n, *tmpa=rank, *tmpb=height; int i,j,k,len=0,num=0,zero=0,one=(n+1)/3; for(i=0;i<n;++i) if(i%3)tmpa[len++]=i; str[n]=str[n+1]=0; radixsort(str+2, tmpa, tmpb, len, m); radixsort(str+1, tmpb, tmpa, len, m); radixsort(str+0, tmpa, tmpb, len, m); nstr[F(tmpb[0])]=num++; for(i=1;i<len;++i) nstr[F(tmpb[i])]=equal(str,tmpb[i-1],tmpb[i])?num-1:num++; if(num<len)dc3(nstr,nsa,len,num); else for(i=0;i<len;++i) nsa[nstr[i]]=i; if(n%3==1)tmpa[zero++]=n-1; for(i=0;i<len;++i)if(nsa[i]<one)tmpa[zero++]=nsa[i]*3; radixsort(str, tmpa, tmpb, zero, m); for(i=0;i<len;++i)tmpa[nsa[i]=G(nsa[i])]=i; i=j=0; for(k=0;k<n;++k) if(j>=len||(i<zero&&cmp3(str,tmpa,tmpb[i],nsa[j])))sa[k]=tmpb[i++]; else sa[k]=nsa[j++]; } bool cmp(int *str, int a, int b, int k) { return str[a]==str[b]&&str[a+k]==str[b+k]; } void da(int *str, int *sa, int n, int m) { int *x=rank, *y=height; int i,j,k,num=1; /** 获取长度为1的结果*/ for(i=0;i<n;++i)y[i]=i; radixsort(str,y,sa,n,m); for(i=0;i<n;++i)x[i]=str[i]; for(i=0;i<n;++i)x[i+n]=y[i+n]=-1; /** 循环排序直到结果唯一或2^k大于n*/ for(k=1;num<n;k<<=1,m=num) { /** 通过k-1的结果或得当前结果*/ num=j=0; for(i=max(0,n-k);i<n;++i) y[j++]=i; for(i=0;i<n;++i)if(sa[i]>=k)y[j++]=sa[i]-k; radixsort(x,y,sa,n,m); swap(x,y); /** 通过当前结果得到新字符串*/ x[sa[0]]=num++; for(i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?num-1:num++; } } void initSA(T *s, int n,int m) { int i,j,k=0; str[len=n]=0;//末尾增加一个0,这样就省去一些特殊情况的讨论,也就是最后一个mod 3刚好等于0 for(i=0;i<n;++i)str[i]=s[i]; dc3(str,sa,n+1,m); for(i=0;i<n;++i)sa[i]=sa[i+1];//第0小的默认为最后一个字符0,所以答案向前移动一位,da算法不用 //da(str,sa,n,m); for(i=0;i<n;++i)rank[sa[i]]=i; for(i=0;i<n;++i)//计算height数组 { if(k)--k; if(rank[i])for(j=sa[rank[i]-1];str[i+k]==str[j+k];++k); else k=0; height[rank[i]]=k; } } void initRMQ() { int i,j; for(i=0;i<len;++i)best[i][0]=height[i]; for(j=1;(1<<j)-1<len;++j) for(i=0;i+(1<<j)-1<len;++i) best[i][j]=min(best[i][j-1],best[i+(1<<(j-1))][j-1]); } int RMQ(int l, int r) { int k=0; while(l+(1<<k)-1+1<r-(1<<k)+1)++k; return min(best[l][k],best[r-(1<<k)+1][k]); } int LCPSA(int a, int b) { if(a==b)return len-sa[a]; if(++a>b)swap(a,b); return RMQ(a,b); }};
/******************************************************************** 后缀数组 Suffix Array** INIT:solver.call_fun(char* s);** CALL: solver.lcp(int i,int j); //后缀i与后缀j的最长公共前缀** SP_USE: solver.LCS(char *s1,char* s2); //最长公共字串******************************************************************/struct SuffixArray{ int r[maxn]; int sa[maxn],rank[maxn],height[maxn]; int t[maxn],t2[maxn],c[maxn],n; int m;//模板长度 void init(char* s){ n=strlen(s); for (int i=0;i<n;i++) r[i]=int(s[i]); m=300; } int cmp(int *r,int a,int b,int l){ return r[a]==r[b]&&r[a+l]==r[b+l]; } /** 字符要先转化为正整数 待排序的字符串放在r[]数组中,从r[0]到r[n-1],长度为n,且最大值小于m。 所有的r[i]都大于0,r[n]无意义算法中置0 函数结束后,结果放在sa[]数组中(名次从1..n),从sa[1]到sa[n]。s[0]无意义 **/ void build_sa(){ int i,k,p,*x=t,*y=t2; r[n++]=0; for (i=0;i<m;i++) c[i]=0; for (i=0;i<n;i++) c[x[i]=r[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=1;k<n;k*=2,m=p){ for (p=0,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++; } n--; } /** height[2..n]:height[i]保存的是lcp(sa[i],sa[i-1]) rank[0..n-1]:rank[i]保存的是原串中suffix[i]的名次 **/ void getHeight(){ int i,j,k=0; for (i=1;i<=n;i++) rank[sa[i]]=i; for (i=0;i<n;i++){ if (k) k--; j=sa[rank[i]-1]; while (r[i+k]==r[j+k]) k++; height[rank[i]]=k; } } int d[maxn][20]; //元素从1编号到n void RMQ_init(int A[],int n){ for (int i=1;i<=n;i++) d[i][0]=A[i]; for (int j=1;(1<<j)<=n;j++) for (int i=1;i+j-1<=n;i++) d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]); } int RMQ(int L,int R){ int k=0; while ((1<<(k+1))<=R-L+1) k++; return min(d[L][k],d[R-(1<<k)+1][k]); } void LCP_init(){ RMQ_init(height,n); } int lcp(int i,int j){ if (rank[i]>rank[j]) swap(i,j); return RMQ(rank[i]+1,rank[j]); } void call_fun(char* s){ init(s);//初始化后缀数组 build_sa();//构造后缀数组sa getHeight();//计算height与rank LCP_init();//初始化RMQ } int LCS(char* s1,char* s2){ int p,ans; int l=strlen(s1); p=l; s1[l]='$'; s1[l+1]='\0'; strcat(s1,s2); call_fun(s1); ans=0; for (int i=2;i<=n;i++) if ((sa[i-1]<p&&sa[i]>p)||(sa[i-1]>p&&sa[i]<p)) ans=max(ans,height[i]); return ans; }}solver;
0 0
- 【后缀数组】后缀数组模板
- 后缀数组【模板】
- 【后缀数组模板】
- 后缀数组模板
- 后缀数组模板
- 【模板】后缀数组
- 后缀数组模板
- 后缀数组模板
- 后缀数组模板
- 【省选】【后缀数组】模板
- 后缀数组 模板
- 后缀数组 模板
- 后缀数组模板
- 后缀数组模板
- 后缀数组模板
- 后缀数组模板
- 后缀数组模板
- 模板-后缀数组
- POJ 3255 Roadblocks
- Fibonacci 0,1,1,2,3,5,8…… 数列的实现
- hdu2504
- CSS浮动(float,clear)通俗讲解- 杨元- 博客园
- UVa OJ 160 Factors and Factorials
- 后缀数组模板
- Orcfile文件格式解析
- 关于时间模糊查询的三种方法
- 计算机的武侠
- 快速寻找满足条件的两/三个数
- POJ 1422Air Raid(二分图最大匹配之最小路径覆盖)
- scala akka 修炼之路3(基于java nio的socket编程)
- linux eth0
- 前/中/后缀表达式的转换