后缀数组 - poj2774 Long Long Message
2015-09-02 11:22
489 查看
题目:
http://poj.org/problem?id=2774题意:
给两个字符串,求最大公共子串的长度思路:
后缀数组模板题,我是拿这题来入门后缀数组的在两个字符串中插入一个比两个字符串中任一字符小的字符,在本题中即插入一个('a'-1),然后合并两个字符串,在其他题解中会看到,当合并多个字符串时,要在每个间隔都加上一个不同的逼所有字符串中任一字符小的字符。然后对合并完的字符串求后缀数组,因为间隔字符的存在,height数组中记录的lcp值不会越过第一个字符串到达第二个,这一点很重要,一定要理解为什么要插入不同的字符,而保证插入字符小于串中任意字符是为了保证,每个字符串的后缀数组能够与独立情况下求得的后缀数组一致,因为在独立情况下,字符串结尾字符为'\0',即默认结尾字符小于任一字符。之后遍历height数组,找到lcp最大,且两个后缀串分别位于第一个和第二个字符串的后缀即可
代码:
#include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #define rep(i,n) for(int i = 0;i < n; i++) using namespace std; const int MAXSIZE = 2*1e6 + 100; int rk[MAXSIZE],sa[MAXSIZE],height[MAXSIZE],wa[MAXSIZE],res[MAXSIZE]; char w[MAXSIZE]; int len; void getSa (int up) { int *k = rk,*id = height,*r = res, *cnt = wa; rep(i,up) cnt[i] = 0; rep(i,len) cnt[k[i] = w[i]]++; rep(i,up) cnt[i+1] += cnt[i]; for(int i = len - 1; i >= 0; i--) { sa[--cnt[k[i]]] = i; } int d = 1,p = 0; while(p < len){ for(int i = len - d; i < len; i++) id[p++] = i; rep(i,len) if(sa[i] >= d) id[p++] = sa[i] - d; rep(i,len) r[i] = k[id[i]]; rep(i,up) cnt[i] = 0; rep(i,len) cnt[r[i]]++; rep(i,up) cnt[i+1] += cnt[i]; for(int i = len - 1; i >= 0; i--) { sa[--cnt[r[i]]] = id[i]; } swap(k,r); p = 0; k[sa[0]] = p++; rep(i,len-1) { if(sa[i]+d < len && sa[i+1]+d < len && r[sa[i]] == r[sa[i+1]] && r[sa[i]+d] == r[sa[i+1]+d]) k[sa[i+1]] = p - 1; else k[sa[i+1]] = p++; } if(p >= len) return ; d <<= 1,up = p, p = 0; } } void getHeight() { int i,k,h=0; rep(i, len) rk[sa[i]]=i; rep(i, len){ if (rk[i]==0) h=0; a494 else { k=sa[rk[i]-1]; if (h) h--; while (w[i+h] == w[k+h]) h++; } height[rk[i]]=h; } } int l; char s[MAXSIZE], t[MAXSIZE]; void getSuffix(char s[]) { l = strlen(s); s[l] = 'a' - 1; s[l+1] = 0; strcat(s,t); //cout<<s<<endl; len = strlen(s); int up = 0; for(int i = 0; i < len; i++) { w[i] = s[i] - 'a' + 2; up = up > w[i] ? up : w[i]; } w[len+1] = 0; getSa(up+1); getHeight(); } int main(){ scanf("%s",s); scanf("%s",t); getSuffix(s); int maxinum = 0; for (int i=1;i<len;++i){ if (height[i]>maxinum) if ((sa[i-1]<l && sa[i]>l) || (sa[i-1]>l && sa[i]<l)) maxinum = height[i]; } cout<<maxinum<<endl; return 0; }
相关文章推荐
- Hibernate学习笔记
- Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()
- 自我总结:找工作面试时注意事项
- docker+tomcat+java配置(ubuntu)
- 36辆自动赛车和6条跑道的问题
- jquery学习笔记----ajax使用
- MySQL二进制日志
- jQuery实现自定义右键菜单的树状菜单效果
- PAT-01-复杂度2 Maximum Subsequence Sum
- nginx 多个80端口转发
- U-BOOT移植心得
- 设置子视图Alpha不同于父视图
- AJAX+js实现实时聊天
- Multi-Master Replication Manager for MySQL FAQ
- hibernate4 could not initialize proxy - no Session
- MySQL二进制日志
- C/C++存储区划分
- Android系统SVC命令教程
- 现阶段要学习JAVA技术
- C# List<string>如何根据分隔符合并成字符串