TYVJ 1860 后缀数组入门模版题
2013-10-30 18:16
288 查看
题意:。。。。。
另一种版本C++已经封装:
第一种效率最快哦。
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn = 200000 + 10; const int sigma_size = 27; //擦,少了个桶子 我悲剧了30次。。。。 /* *suffix array *倍增算法 O(n*logn) *待排序数组长度为n,放在0~n-1中,在最后面补一个0 *build_sa( ,n+1, );//注意是n+1; *getHeight(,n); *例如: *n = 8; *num[] = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最后一位为0,其他大于0 *rank[] = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };rank[0~n-1]为有效值,rank 必定为0无效值 *sa[] = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]为有效值,sa[0]必定为n是无效值 *height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]为有效值 * */ int sa[maxn],t1[maxn],t2[maxn],c[maxn]; int Rank[maxn],height[maxn]; void build_sa(int s[],int n,int m) { int i,j,p,*x=t1,*y=t2; 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(j=1;j<=n;j<<=1) { p=0; for(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++) 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]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++; if(p>=n) break; m=p; } } void getHeight(int s[],int n) { int i,j,k=0; for(i=0;i<=n;i++) Rank[sa[i]]=i; for(i=0;i<n;i++) { if(k) k--; j=sa[Rank[i]-1]; while(s[i+k]==s[j+k]) k++; height[Rank[i]]=k; } } char str[maxn]; int S[maxn]; int main() { while(~scanf("%s",str)){ int n=strlen(str); for(int i=0;i<n;i++) S[i]=str[i]-'a'+1; build_sa(S,n+1,sigma_size); getHeight(S,n); for(int i=1;i<n;i++) printf("%d ",sa[i]+1); printf("%d\n",sa +1); for(int i=1;i<n;i++) printf("%d ",height[i]); printf("%d\n",height ); } return 0; }
另一种版本C++已经封装:
#include <cstdio> #include <cstring> #include <string> #include <set> #include <algorithm> using namespace std; /* 时间复杂度:O(nlogn) * 注意点 * 1.insert进的全部数都必须大于0,如出现特殊情况,可根据题意将原数加上某个数使之大于0 * 2.getsa()函数中的m默认为256 m = max{ init[i] } + 1 可根据题意更改 * 3.输入的数据从下标0开始存储在init数组,第size位则手动添加上个0 * 4.询问lcp时输入a,b必须不同 */ class SuffixArray { public: static const int maxn= 200000 + 10; int init[maxn]; //将初始数据,保存在init里,并且保证每个数字都比0大 int X[maxn]; int Y[maxn]; int Rank[maxn]; //名次数组,从0开始 int sa[maxn]; //sa从1开始,因为最后一个字符(最小的)排在第0位 int high[maxn]; //high从1开始,因为表示的是sa[i]和sa[i+1] [0,size) int buc[maxn]; int log2[maxn]; int best[maxn][20]; int size; //初始数据个数 void clear() { size=0; } //输入一个数 void insert(int n) { init[size++]=n; } bool cmp(int *r,int a,int b,int l) { return (r[a]==r[b]&&r[a+l]==r[b+l]); } //当需要反复询问两个后缀的最长公共前缀时用到RMQ //n为字符串长度,m为最大值一般256 void getsa(int m=256) { init[size]=0; int i,l,p,*x=X,*y=Y,n=size+1; for(i=0;i<m;i++) buc[i]=0; for(i=0;i<n;i++) buc[x[i]=init[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++; } } void gethigh() { int i,j,h=0,n=size; for(i=1;i<=n;i++) Rank[sa[i]]=i; high[0]=0; for(i=0;i<n;i++) { if(h>0) h--; j=sa[Rank[i]-1]; for(;i+h<n&&j+h<n&&init[i+h]==init[j+h];h++); high[Rank[i]-1]=h; } } //预处理每个数字的Log值,常数优化,用于RMQ void initLog() { int i; log2[0]=-1; for(i=1;i<maxn;i++) log2[i]=(i&(i-1))?log2[i-1]:log2[i-1]+1; } //初始化RMQ void initRMQ() { int i,j,limit,n=size; initLog(); for(i=0;i<n;i++) best[i][0]=high[i]; for(j=1;j<=log2 ;j++) { limit=n-(1<<j); for(i=0;i<=limit;i++) best[i][j]=min(best[i][j-1],best[i+(1<<j-1)][j-1]); } } //询问a,b后缀的最长公共前缀 用lcp之前,先初始化RMQ int lcp(int a,int b) { int t; a=Rank[a]; b=Rank[b]; if(a>b) swap(a,b); b--; t=log2[b-a+1]; return min(best[a][t],best[b-(1<<t)+1][t]); } }SA; char s[200010]; int main() { int i,len; while(~scanf("%s",s)) { SA.clear(); len=strlen(s); for(i=0;i<len;i++) SA.insert(s[i]-'a'+1); SA.getsa(); SA.gethigh(); printf("%d",SA.sa[1]+1); for(i=2;i<=len;i++) printf(" %d",SA.sa[i]+1); printf("\n"); printf("%d",SA.high[0]); for(i=1;i<len;i++) printf(" %d",SA.high[i]); printf("\n"); } return 0; }
第一种效率最快哦。
相关文章推荐
- tyvj 1860 后缀数组入门题
- tyvj1860 后缀数组 模板
- TYVJ 1860 后缀数组裸题
- 【tyvj1860】后缀数组
- tyvj 1860后缀数组
- 【tyvj 1860】 后缀数组模板
- Tyvj 1860 后缀数组 [Suffix Array 裸题]
- [Tyvj 1860] 后缀数组 倍增O(nlogn) 求sa[],height[]模板
- 后缀数组模版 及 可重叠和不可重叠最长重复子串【for_wind】
- Long Long Message(poj2274,后缀数组入门)
- 后缀数组的DC3模版【后缀数组】
- HDU1403 Longest Common Substring(最长公共子串、后缀数组入门)
- uoj#35 后缀排序(后缀数组模版)
- URAL 1517 Freedom of Choice 后缀数组 入门
- 后缀数组入门题——2323后缀排序
- 后缀数组求lcp(模版,st模版把
- 后缀数组模版O(N*2个log)求Sa[i]+字符串查找
- hdu 1403 后缀数组入门题
- HDU 3518 Boring counting(后缀数组入门题)
- POJ2774 Long Long Message(后缀数组入门题)