后缀数组模板
来源:互联网 发布:java校园招聘面试题 编辑:程序博客网 时间:2024/04/28 09:52
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;const int maxn = 1000;int rank[maxn],wb[maxn],wv[maxn],wss[maxn];int n;bool 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){ int i,j,p,*x=rank,*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 main(){ int a; a = 2; char s[1000],l; int r[1000],sa[1000],i; while(scanf("%s",s) == 1) { puts(s); l = strlen(s); l++; for(i=0; i<l-1; i++) r[i] = s[i]-'a'+1; r[l-1] = 0; da(r,sa,l,27); //------------------------------------------ for(i=0; i<l-1; i++) // rank[i] : suffix(i)排第几 printf("rank[%d] = %d\n",i,rank[i]); printf("\n"); for(i=0; i<l; i++) // sa[i] : 排在第i个的是谁 printf("sa[%d] = %d\n",i,sa[i]); //------------------------------------------ } return 0;}
求height[i]:相邻后缀的最长公共前缀的模板
POJ3693:求重复次数最多的连续重复子串。(并且含有RMQ,Log数组尤其给力)
#include<iostream>#include<cstdio>#include<vector>#include<cstring>using namespace std;const int nMax =1000012;int num[nMax];int sa[nMax], rank[nMax], height[nMax];int wa[nMax], wb[nMax], wv[nMax], wd[nMax];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 n, int m){ // 倍增算法 r为待匹配数组 n为总长度 m为字符范围 int i, j, p, *x = wa, *y = wb, *t; for(i = 0; i < m; i ++) wd[i] = 0; for(i = 0; i < n; i ++) wd[x[i]=r[i]] ++; for(i = 1; i < m; i ++) wd[i] += wd[i-1]; for(i = n-1; i >= 0; i --) sa[-- wd[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 ++) wd[i] = 0; for(i = 0; i < n; i ++) wd[wv[i]] ++; for(i = 1; i < m; i ++) wd[i] += wd[i-1]; for(i = n-1; i >= 0; i --) sa[-- wd[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 ++; } }}void calHeight(int *r, int n){ // 求height数组。 int i, j, k = 0; for(i = 1; i <= n; i ++) rank[sa[i]] = i; // 1->n for(i = 0; i < n; i++){ for(k ? k -- : 0, j = sa[rank[i]-1]; r[i+k] == r[j+k]; k ++); height[rank[i]] = k; } /* for(i=0; i<n; i++) printf("i=%d height[i]=%d\n",i,height[i]); */}int Log[nMax];int best[20][nMax];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]);}char str[nMax];int ans[nMax];int main(){ int i,j,n,cas=0;Log[0] = -1;for(int i=1;i<=nMax;i++){ // 求log2,这么强大的位运算。。Log[i]=(i&(i-1))?Log[i-1]:Log[i-1] + 1 ;/*if(i <= 40) printf("i=%d Log[i]=%d\n",i,Log[i]);*/} while(scanf("%s",str)!=EOF&&str[0]!='#'){ n=strlen(str); /*----------------------------*/ for(i=0;i<n;i++){ num[i]=str[i]-'a'+1; }num[n]=0; da(num, n + 1,30); /* for(i=0; i<=n; i++) // <= not <!!! printf("i=%d sa[i]=%d\n",i,sa[i]); */ /*----------------------------*/ calHeight(num,n); initRMQ(n); int l,r,t,k,maxx=-1,a; for(l=1;l<n;l++){ //枚举长度 for(i=0;i+l<n;i+=l){ k=lcp(i,i+l); r=k/l+1; t=l-k%l; t=i-t; if (t>=0&&k%l!=0){ if(lcp(t,t+l)>=k) r++; } if(r>maxx){ a=0; maxx=r; ans[a++]=l; } if(a==maxx){ ans[a++]=l; } } } int start,b=0,c; for(i=1;i<=n&&!b;i++){ //sa数组是保证字典序的神器啊 Orz for(j=0;j<a;j++){ int tl=ans[j]; if(lcp(sa[i],sa[i]+tl)>=(maxx-1)*tl){ start=sa[i]; l=tl*maxx; b=1; break; } } } printf("Case %d: ",++cas); for (int i=0;i<l;i++) printf("%c",str[start+ i]); printf("\n"); } return 0;}
- 【后缀数组】后缀数组模板
- 后缀数组【模板】
- 【后缀数组模板】
- 后缀数组模板
- 后缀数组模板
- 【模板】后缀数组
- 后缀数组模板
- 后缀数组模板
- 后缀数组模板
- 【省选】【后缀数组】模板
- 后缀数组 模板
- 后缀数组 模板
- 后缀数组模板
- 后缀数组模板
- 后缀数组模板
- 后缀数组模板
- 后缀数组模板
- 模板-后缀数组
- minix文件锁管理
- 使用ctr+c无法终止一个bash脚本,此脚本在循环执行一个需要运行一定时间的命令
- 关系循环语句的条件判断2012-10-29
- 分页计算标签功能之------序号按纸重新排列
- 指定第一个和最后一个触发器
- 后缀数组模板
- Android 获取SDCard上图片和视频的缩略图
- 单元格超链接传递参数组
- 项目二 分数的累加
- RGB2YUV420
- 点集中的最近点 最远点对
- SQL中Null值求和
- XXX.exe 中的 0x77c615de 处未处理的异常: 0xC00000FD: Stack overflow
- 二进制、八进制、十六进制的前生今世